Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.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_Unix - Fatal编程技术网

C++ C套接字发送/接收缓冲区类型

C++ C套接字发送/接收缓冲区类型,c++,c,sockets,unix,C++,C,Sockets,Unix,我正在使用unix套接字,当我的缓冲区类型为char(即发送和接收字符串)时,我可以发送()和recv()数据。我使用了Beej的套接字指南,其中的示例用于发送/接收字符串 现在我想在一条消息中发送/接收不同类型的数据。 例如,在一条消息中,我想发送一个整数、一个字符串、一个双精度和一个浮点。 我该怎么做呢?更具体地说,我的消息“缓冲区”应该是什么类型 发送和接收的原型: int recv (int socket, void *buffer, size_t size, int flags) in

我正在使用unix套接字,当我的缓冲区类型为char(即发送和接收字符串)时,我可以发送()和recv()数据。我使用了Beej的套接字指南,其中的示例用于发送/接收字符串

现在我想在一条消息中发送/接收不同类型的数据。
例如,在一条消息中,我想发送一个整数、一个字符串、一个双精度和一个浮点。 我该怎么做呢?更具体地说,我的消息“缓冲区”应该是什么类型

发送和接收的原型:

int recv (int socket, void *buffer, size_t size, int flags)
int send (int socket, void *buffer, size_t size, int flags)
我在C/C++和指针方面没有太多的经验,所以这可能是一个noob问题

如果有人能给我指引正确的方向,我将不胜感激。
谢谢

最好的方法是将要传递的信息封装在一个结构中。然后传递结构的地址和长度。请注意,
buffer
是一个
void*
,因此允许您传递包含信息的结构的地址

下面是我用于安全复制类工具的
struct
的一个小片段

然后在
send_message()
中序列化
消息
,然后将
写入
套接字

bool send_message(const struct message *msg, const char *ip, const char *port)
{
    ...
   connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
   // Serialize to file
   serialize(msg, "temp");

   // Transfer the file over the network
   fp = fopen("temp", "rb");
   while((n = fread(buffer, 1, MAX_BUF_LEN, fp)) != 0)
   {
       write(sockfd, buffer, n);
   }

   fclose(fp);
   remove("temp");

   close(sockfd);
}

正如@vitaut所建议的,您可以使用库来
序列化
,我将其作为一种学习体验来实现。

您需要在发送方创建对象,在接收方进行反序列化。例如,C++中有许多库,或者如果你想重新发明轮子,你可以随时滚动自己。

这取决于这是多么便携。 最简单的方法是将所有内容转换为用逗号或分号分隔的ASCII,然后在接收端再次解析它


您还可以将其转换为二进制文件并以二进制文件的形式发送。

除非您计划发送大量数据(许多千字节),通常(每秒数个数据包),否则我建议您将数据转换为字符串(也称为“序列化数据”)并以这种方式传递。它有几个好处:

  • 它是可移植的-无论
    int
    float
    double
    的大小如何,或者结构中字段之间的填充是什么,它都可以工作
  • 调试很容易(您只需查看数据并判断数据是否正确)
  • 发送/接收机器的字节顺序并不重要
    另一方面,发送二进制数据是复杂的,因为您需要考虑数据字段的各个大小及其内部表示(字节顺序、双精度(
    double
    如何在二进制中表示、在结构中填充数据字段、无法传递指针等)。唯一的好处是二进制数据更加紧凑。但只有当你有很多千字节和/或每秒发送很多数据包时,这才重要

    好吧,要回答问题(“如何发送结构?”),只需发送一个指向结构的指针

    struct foo
    {
      int a;
      int b;
    };
    
    struct foo s;
    s.a = 10;
    s.b = 20;
    send(socket,&s,sizeof(s),0);
    
    这真的很容易。现在,另一侧必须相同(也就是说,系统A内存中的结构必须与系统B中的结构相匹配)。更好的方法是使用更具体的类型和一些函数来正确排序数据:

    #ifndef __GNUC__
    #  define __attribute__(x)
    #endif
    
    #ifdef __SunOS
    #  pragma pack(1)
    #endif
    
    struct foo
    {
      uint32_t a;
      uint32_t b;
    } __attribute__((packed));
    
    #ifdef __SunOS
    #  pragma pack()
    #endif
    
    struct foo s
    
    /* to send */
    
    s.a = htonl(10);
    s.b = htonl(20);
    send(socket,&s,sizeof(s),0);
    
    /* to receive */
    recv(socket,&s,sizeof(s),0);
    s.a = ntohl(s.a);
    s.b = ntohl(s.b);
    

    <>你可以看到,当你想“便携”地通过网络发送二进制数据时,它开始变得特别系统化,这就是为什么人们说要转换成文本,或者很可能使用已经编写的序列化库。

    确保考虑串行化浮点值的问题:我同意这个建议,但将
    双精度
    浮点
    序列化为字符串时仍需小心,以避免四舍五入问题。是的,处理浮点数总是有点乱——它们只是不太便于用户使用(至少如果您想获得全精度,就不需要这样做)。
    #ifndef __GNUC__
    #  define __attribute__(x)
    #endif
    
    #ifdef __SunOS
    #  pragma pack(1)
    #endif
    
    struct foo
    {
      uint32_t a;
      uint32_t b;
    } __attribute__((packed));
    
    #ifdef __SunOS
    #  pragma pack()
    #endif
    
    struct foo s
    
    /* to send */
    
    s.a = htonl(10);
    s.b = htonl(20);
    send(socket,&s,sizeof(s),0);
    
    /* to receive */
    recv(socket,&s,sizeof(s),0);
    s.a = ntohl(s.a);
    s.b = ntohl(s.b);