Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通过C+中的套接字传输数据+;_C++_C_Sockets_Serialization_Tcp - Fatal编程技术网

C++ 通过C+中的套接字传输数据+;

C++ 通过C+中的套接字传输数据+;,c++,c,sockets,serialization,tcp,C++,C,Sockets,Serialization,Tcp,我目前正在从事一个使用网络的项目。我必须发送一个结构 struct Header { uint32_t magic; uint32_t checksum; uint32_t timestamp; uint16_t commandId; uint16_t dataSize; }; struct Packet { struct Header header; char

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

    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);
但它不起作用,所以我尝试将结构序列化为字符*

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));
    }
即使客户端同时发送结构头数据,当我在服务器端读取时,数据也会损坏 为什么数据会损坏

客户端发送循环

    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());
}
套接字->读取():

当我运行这些程序时:

    ./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
  • 每次只需屏蔽低8位:

    buffer[3] = (arg >> 24) & 0xff;
    buffer[2] = (arg >> 16) & 0xff;
    buffer[1] = (arg >> 8) & 0xff;
    buffer[0] = (arg) & 0xff;
    
  • 反序列化时也要执行同样的操作


  • 如果我是你,我就不会重新发明轮子。有很多经过良好记录和测试的库/协议正是为了满足您的需求。我刚刚想到的一个小清单:

    • JSON
    • XML
    • 科尔巴

      • 因此,这是错误的,它肯定会导致错误

        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()
        的返回值。 从
        man 2 recv

        RETURN VALUES These calls return the number of bytes received, or -1 if an error occurred. For TCP sockets, the return value 0 means the peer has closed its half side of the connection. 返回值 这些调用返回接收到的字节数,如果出现错误,则返回-1 发生。 对于TCP套接字,返回值0表示对等方已关闭其一半 连接的一侧。 那么,您收到了多少字节?如果放弃
        recv()
        的结果,则无法判断。可能
        recv()
        失败了,如果不检查返回值,您将永远不会发现。也许它只填满了你的一部分缓冲区。您必须检查
        recv()
        中的返回代码。这是人们在编写使用TCP的程序时犯的第一个错误

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

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

      • recv()
        调用可能会部分填充缓冲区

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

      • recv()
        调用可能指示
        EINTR
        ,因为它被系统调用中断

      • recv()
        调用可能指示
        econreset
        ,因为发送方突然关闭了连接或已消失

      • recv()
        调用可能会遇到其他错误



      • 请记住:在使用TCP时,仅仅因为您
        send()
        16字节,并不意味着另一个对等方将
        recv()
        16字节-它可能会被分成块。TCP是一种流协议。与UDP不同,相邻的数据块可以任意合并或拆分。

        我们假设客户机是以正确的反向算法解包的(请注意,您应该使用
        unsigned char
        作为包缓冲区)。此外,第一种情况下的结构打包以及机器端位格式也将发挥作用。对于uint16和uint32,您可以只使用ntohl、ntohs、htonl和htons。简单的回答是:您必须在字节级别精确定义数据格式,并在发送和接收时正确地转换为“有线格式”。@DavidSchwartz我同意,但几天前,当我为一个类似的问题提出解决方案时,我立即跳到了另一边,因为它不存在“标准”。仍然与此不同。(顺便说一句,我仍然会使用POSIX函数,就像你可能会做的那样)。有两个明显的问题。首先,send(socket,&my_struct,sizeof(my_struct))不起作用,因为send()需要四个参数。其次,序列化应该使用无符号字符(即“byte”)正如已经指出的那样,“网络”功能可以避免端点问题,而不是字符。WhozCraig:由于这个问题被标记为
        C
        C++
        ,并使用
        uint32\u t
        ,我无法想象“标准”是什么“可能是……)你能解释一下为什么缓冲区会被签名吗?这个答案是错误的。这里的屏蔽在任何具有8位字节的平台上都不会起任何作用。由于
        arg
        buffer
        都是无符号的,因此根据C标准,所有算法都是模块化的。因此,如果
        x
        具有类型
        unsigned char
        ,并且
        unsigned char
        具有8位,则
        x=arg
        x=arg&0xff
        产生完全相同的结果。@DietrichEpp-给出答案时,问题指定缓冲区是有符号的,这个问题是在回答后两个小时编辑的。@BinyaminSharet:当然,但即使签名,也不会对两个补码平台产生影响,例如所有平台。我知道,但我正在做一个学校项目,我们不允许使用任何库,也不能使用文本协议:(请定义“库”?C库是库吗?(例如,您允许使用htonX/ntohX函数吗?)我们允许使用libc htons/htonl&ntohX,但我从未使用过它们,我不知道如何使用它们。)to@WhozCraig:我认为没有粗体也可以。我的客户端发送返回值为17,服务器接收返回值也为17:(@camiletolsa:我想你误解了。没有必要告诉我返回值是什么,因为每次返回值都可能不同。你必须修改你的程序,使它能够正确地处理
        recv()
        可以给出的每个返回值。我理解,但我使用循环缓冲来处理案例[1]&[2],案例[3]是句柄,案例[4]、[5]或[6]在我的测试中从未出现过。@CamilleTolsa:尝试使用Valgrind运行客户端和服务器。由于您尚未发布至少处理案例1和案例2的固定代码,我无法知道它是否正确。
        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);
        }
        
        RETURN VALUES These calls return the number of bytes received, or -1 if an error occurred. For TCP sockets, the return value 0 means the peer has closed its half side of the connection.