【问题标题】:how can read() put 32bit ints in a buffer?read() 如何将 32 位整数放入缓冲区?
【发布时间】:2020-04-24 11:27:19
【问题描述】:

我有以下程序(几乎是 GNU 手册中的示例),它打开 TCP 套接字,等待连接,然后逐字节打印接收到的数据。或者我是这么想的……

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define PORT    19000
#define MAXMSG  512


int
make_socket (uint16_t port)
{
  int sock;
  struct sockaddr_in name;

  /* Create the socket. */
  sock = socket (PF_INET, SOCK_STREAM, 0);
  if (sock < 0)
    {
      perror ("socket");
      exit (EXIT_FAILURE);
    }

  /* Give the socket a name. */
  name.sin_family = AF_INET;
  name.sin_port = htons (port);
  name.sin_addr.s_addr = htonl (INADDR_ANY);
  if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
    {
      perror ("bind");
      exit (EXIT_FAILURE);
    }

  return sock;
}

int
read_from_client (int filedes)
{
  char buffer[MAXMSG];
  int nbytes;

  nbytes = read (filedes, buffer, MAXMSG);
  if (nbytes < 0)
    {
      /* Read error. */
      perror ("read");
      exit (EXIT_FAILURE);
    }
  else if (nbytes == 0)
    /* End-of-file. */
    return -1;
  else
    {
      /* Data read. */
      fprintf (stderr, "Server: got message:\n");
      for (int i = 0; i < nbytes; i++) {
        printf(" %02x", buffer[i] & 0xff);
      }
      printf("\n");

      return 0;
    }
}

int
main (void)
{
  extern int make_socket (uint16_t port);
  int sock;
  fd_set active_fd_set, read_fd_set;
  int i;
  struct sockaddr_in clientname;
  size_t size;

  /* Create the socket and set it up to accept connections. */
  sock = make_socket (PORT);
  if (listen (sock, 1) < 0)
    {
      perror ("listen");
      exit (EXIT_FAILURE);
    }

  /* Initialize the set of active sockets. */
  FD_ZERO (&active_fd_set);
  FD_SET (sock, &active_fd_set);

  while (1)
    {
      /* Block until input arrives on one or more active sockets. */
      read_fd_set = active_fd_set;
      if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0)
        {
          perror ("select");
          exit (EXIT_FAILURE);
        }

      /* Service all the sockets with input pending. */
      for (i = 0; i < FD_SETSIZE; ++i)
        if (FD_ISSET (i, &read_fd_set))
          {
            if (i == sock)
              {
                /* Connection request on original socket. */
                int new;
                size = sizeof (clientname);
                new = accept (sock,
                              (struct sockaddr *) &clientname,
                              (socklen_t *)&size);
                if (new < 0)
                  {
                    perror ("accept");
                    exit (EXIT_FAILURE);
                  }
                fprintf (stderr,
                         "Server: connect from host %s, port %hd.\n",
                         inet_ntoa (clientname.sin_addr),
                         ntohs (clientname.sin_port));
                FD_SET (new, &active_fd_set);
              }
            else
              {
                /* Data arriving on an already-connected socket. */
                if (read_from_client (i) < 0)
                  {
                    close (i);
                    FD_CLR (i, &active_fd_set);
                  }
              }
          }
    }
}

当我运行它并且客户端连接并发送数据时,它看起来像这样:

Server: connect from host 10.6.65.167, port -8348.
Server: got message:
 ffffffcc ffffffdd ffffffee ffffffff 15 27 00 00 04 13 69 00 ffffff9c 00 00 00 00 00 00 00 ffffffb4 ffffffee ffffffb9 3b 00 00 34 30 36 41 38 45 35 41 45 39 35 31 31 31 31 31 31 50 57 32 41 32 45 30 36 45 2d 47 59 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 30 31 39 61 38 64 62 64 34 64 65 35 64 66 61 62 63 31 61 65 30 37 39 33 63 30 32 37 62 38 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Server: got message:
 ffffffcc ffffffdd ffffffee ffffffff 15 27 00 00 04 13 69 00 ffffff9c 00 00 00 00 00 00 00 ffffffb4 ffffffee ffffffb9 3b 00 00 34 30 36 41 38 45 35 41 45 39 35 31 31 31 31 31 31 50 57 32 41 32 45 30 36 45 2d 47 59 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 30 31 39 61 38 64 62 64 34 64 65 35 64 66 61 62 63 31 61 65 30 37 39 33 63 30 32 37 62 38 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...and so on...

为什么我的缓冲区中有 32 位长的“字节”?他们是怎么到达那里的?当我查看 Wireshark 中的网络流量时,如预期的那样,前 4 个字节是“cc”、“dd”、“ee”和“ff”。我很困惑。

【问题讨论】:

  • unsigned char buffer[MAXMSG];替换char buffer[MAXMSG];

标签: c sockets tcp


【解决方案1】:

您收到的数据一切正常。

您对记忆中的数据的解释有问题。

相信你对联合的概念很熟悉。

union {
    int8_t sb[4];
    uint8_t ub[4];
    int16_t ss[2];
    uint16_t us[2];
    float f;
} z;

假设你从套接字流中填充这个变量。

read (d, &z, sizeof(z));

问题是:那个变量是什么?

回答:随便你。

如果您需要将其解释为 4 个有符号字节,那么您可以将数据寻址为 z.sb[0]、z.sb[1]、z.sb[2]、z.sb[3]

当您指示操作系统从网络接收数据时,您如何定义缓冲区无关紧要 - 它只是网络堆栈内存中的字节区域。

但是,当您从内存中获取数据时,如何解释数据确实很重要。 因此,您可以将缓冲区声明为:

unsigned char buffer[MAXMSG];

或使用指向 uint8_t 的指针来寻址缓冲区中的各个字节。

char buffer[MAXMSG];
uint8_t *b=(uint8_t *)buffer;

for (int i = 0; i < nbytes; i++) {
 printf(" %02x", b[i]);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-05
    • 2012-01-28
    • 1970-01-01
    • 2012-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多