当前位置: 首页 > 知识库问答 >
问题:

通过 C 语言中的套接字的数据

羊越
2023-03-14

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

    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));
    }

即使当客户端同步发送一个struct Header数据时,当我在服务器端读取数据时,数据也会损坏。为什么数据会损坏?

客户端发送循环

    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());
}

服务器接收循环:(由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

共有3个答案

夏令秋
2023-03-14

如果我是你,我就不会重新发明轮子。有很多经过良好记录和测试的库/协议,正是为了您想要的目的。我脑海中浮现的一个小清单:

  • 提升序列化
  • 谷歌协议缓冲区
  • 杰伦
  • .XML
  • 科尔巴
慕弘伟
2023-03-14

> < li>

您每次只需屏蔽低8位:

buffer[3] = (arg >> 24) & 0xff;
buffer[2] = (arg >> 16) & 0xff;
buffer[1] = (arg >> 8) & 0xff;
buffer[0] = (arg) & 0xff;

反序列化的时候也这么做

唐法
2023-03-14

所以,这是不对的,肯定会造成误差。

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);
}

来自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 connecthtml" target="_blank">ion.

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

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

>

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

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

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

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

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

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

    记住:使用TCP时,仅仅因为你< code>send() 16字节并不意味着对方会< code>recv() 16字节—

  •  类似资料:
    • 问题内容: 我创建了一个服务器应用程序,该应用程序从客户端接收声音,然后广播此声音,该声音以字节存储,然后将字节发送回连接到服务器的客户端。现在,我目前仅使用一个客户端进行测试,客户端正在接收语音,但是声音一直在卡顿。有人可以告诉我我做错了吗? 我想我理解为什么声音播放不流畅但不了解如何解决问题的部分原因。 代码是波纹管的。 客户端: 将声音发送到服务器的部分 从服务器接收数据字节的部分 问题答案

    • 我有一个客户端和一个服务器。它们通过使用以下命令创建的套接字进行通信: 套接字(AF_INET,SOCK_STREAM,0) 他们之间的交流很好。 我想创建第三个程序,充当服务器并向客户端发送假消息。此程序必须使用以前创建的客户端和服务器套接字。 我使用发送命令与套接字ID由我的静态设置 写入(插座号,消息,1024) 但是它不起作用(我不确定这是正确的方法)。 因此,我尝试了telnet和nc(

    • 本文向大家介绍通过“回文字算法”复习C++语言,包括了通过“回文字算法”复习C++语言的使用技巧和注意事项,需要的朋友参考一下  一、什么是回文字 给定一个字符串,从前往后读和从后往前读,字符串序列不变。例如,河北省农村信用社的客服电话是“96369”,无论从后往前读,还是从前后往后读,各个字符出现的位置不变。 二、功能实现 (一)、给定一个字符串,判断该字符串是否是回文字。 (二)、给定一个任意

    • C 语言中的字符串虽然不是一种独立的数据类型,但是这并不影响其重要地位,所以在 C 语言中会有一些专门针对字符串的函数。 1. 字符串函数 字符串函数是专门用来进行字符串操作的。C 语言提供了一个标准的函数库 string.h 。在这个函数库中大致存在了 22 个字符串的函数。我们这里所介绍的字符串函数是来自于这个标准函数库中比较常用的的一部分函数。除了这个函数库,还会有第三方的函数库提供的字符串

    • 问题内容: 我有2个java netbeans项目,一个是Server,另一个是Client。我已经创建了一个Message类,该类要传递给服务器,并在服务器上进行修改后以另一种方式返回给客户端。我在两个项目中都包含了Message类。我使用和传递对象。服务器和客户端之间的连接正常,并且对象通过,但在服务器上,当我从using 方法读取对象时,将其类型转换为类。但是在服务器上抛出 ClassNot

    • 问题内容: 我正在尝试用Python编写一个实现套接字的程序,每个客户端发送一个PDF文件,服务器接收该文件,标题更改为“ file_number.pdf”(即:file_1.pdf)。出现的问题是只有客户端才能成功发送文件。当第二个客户端尝试发送程序时,它确实崩溃了。我在做什么错,我该如何解决我的代码以允许N个客户端(N <20)连接到服务器并传输文件? 这是服务器代码: 这是客户端代码: 为了