3

我目前正在做一个使用网络的项目。我必须发送一个结构

    struct Header
    {
     uint32_t   magic;
     uint32_t   checksum;
     uint32_t   timestamp;
     uint16_t   commandId;
     uint16_t   dataSize;
    };

    struct Packet
    {
     struct Header  header;
     char       data[128];
    };

我正在尝试使用 TCP 将结构数据包从一个套接字发送到另一个套接字。我试图像这样发送我的结构

      send(socket, &my_struct, sizeof(my_struct), 0);

但它不起作用,所以我尝试将我的结构序列化为 char*

unsigned char               *Serialization::serialize_uint32(unsigned char *buffer, uint32_t arg)
{
 buffer[3] = (arg >> 24);
 buffer[2] = (arg >> 16);
 buffer[1] = (arg >> 8);
 buffer[0] = (arg);
 return (buffer + sizeof(uint32_t));
}

unsigned char               *Serialization::serialize_uint16(unsigned char *buffer, uint16_t arg)
{
 buffer[1] = (arg >> 8);
 buffer[0] = (arg);
 return (buffer + sizeof(uint16_t));
}

    unsigned char                           *Serialization::deserialize_uint32(unsigned char *buffer, uint32_t *arg)
    {
      memcpy((char*)arg, buffer, sizeof(uint32_t));
      return (buffer + sizeof(uint32_t));
    }

    unsigned char                           *Serialization::deserialize_uint16(unsigned char *buffer, uint16_t *arg)
    {
     memcpy((char*)arg, buffer, sizeof(uint16_t));
     return (buffer + sizeof(uint16_t));
    }

即使客户端 symly 发送 struct 标头数据在我读取服务器端时已损坏 为什么数据已损坏?

客户端发送循环

    TcpSocket                     tcp;
    Packet                        p;
    std::stringstream             ss;
    int                           cpt = 0;
    int                           ret = 0;
    char                          *serialized;

    tcp.connectSocket("127.0.0.1", 4242);
    while (getchar())
    {
      ss.str("");
      ss.clear();
  ss << cpt++;
  p.header.magic = 0;
  p.header.checksum = 1;
  p.header.timestamp = 2;
  p.header.commandId = 3;
  p.header.dataSize = ss.str().length();
  memset(p.data, 0, 128);
  memcpy(p.data, ss.str().c_str(), ss.str().length());
  serialized = new char[sizeof(Header) + ss.str().length()];
  bzero(serialized, sizeof(Header) + ss.str().length());
  Serialization::serialize_packet(serialized, p);
  hexDump("serialized", serialized+1, sizeof(Header) + ss.str().length());
  ret = tcp.write(serialized+1, sizeof(Header) + ss.str().length());
}

服务器 recv 循环:(由 select() 调用的函数)

  buff = new char[bav];
  socket->read(buff, bav);
  hexdump("buff", buff, bav);

套接字->读取():

    int                     TcpSocket::read(char *buff, int len)
    {
      int                   ret;

      ret = recv(this->_socket, buff, len, 0);
      return (ret);
    }

当我运行这些程序时:

    ./server
    [Server] new connexion :: [5]
    recv returns : 17
    buff serialized:
      0000  00 00 00 00 14 00 00 00 1c 00 00 00 1a 00 00 00  ................
      0010  1b

    ./client
    serialized data:
      0000  00 00 00 00 00 00 01 00 00 00 02 00 03 00 01 30  ...............0
      0010  00
    send returns : 17
4

3 回答 3

5

所以,这是错误的,它肯定会导致错误。

buff = new char[bav];
socket->read(buff, bav);
hexdump("buff", buff, bav);
socket->read() :

int TcpSocket::read(char *buff, int len)
{
    return recv(this->_socket, buff, len, 0);
}

recv()不能忽略from 的返回值。

来自man 2 recv

返回值
     这些调用返回接收到的字节数,如果出错则返回 -1
     发生了。

     对于 TCP 套接字,返回值 0 表示对端已关闭其一半
     连接的一侧。

那么,你收到了多少字节?如果您丢弃recv(). 也许recv()失败了,如果你不检查返回值,你永远不会发现。也许它只填满了你的缓冲区的一部分。 您必须检查来自recv(). 这是人们在编写使用 TCP 的程序时犯的第一个错误。

您将需要更改代码以处理以下情况:

  1. recv()调用可能会完全填满您的缓冲区。

  2. recv()调用可能会部分填充您的缓冲区。

  3. recv()调用可能返回 0,表示发送方已关闭连接。

  4. recv()调用可能表明EINTR因为它被系统调用中断了。

  5. recv()呼叫可能表明因为发送方ECONNRESET突然关闭了连接或已经消失。

  6. 调用可能会recv()遇到一些其他错误。

记住:当使用 TCP 时,仅仅因为你send()16 字节并不意味着其他对等方将recv()16 字节——它可能被分解成块。TCP 是一种流协议。与 UDP 不同,相邻的数据块可以任意连接或拆分。

于 2012-12-28T00:35:00.060 回答
2
  1. 每次只需要屏蔽低 8 位:

    buffer[3] = (arg >> 24) & 0xff;
    buffer[2] = (arg >> 16) & 0xff;
    buffer[1] = (arg >> 8) & 0xff;
    buffer[0] = (arg) & 0xff;
    
  2. 反序列化时做同样的事情

于 2012-12-27T22:03:22.180 回答
0

如果我是你,我不会重新发明轮子。有很多文档齐全且经过测试的库/协议正是您正在寻找的目的。我想到的一个小清单:

于 2012-12-27T23:12:29.817 回答