在C中,通过具有正确填充和结尾的套接字发送结构

在C中,通过具有正确填充和结尾的套接字发送结构,c,tcp,padding,endianness,struct,C,Tcp,Padding,Endianness,Struct,我定义了几种结构,可以通过不同的操作系统(tcp网络)进行发送。 定义的结构包括: struct Struct1 { uint32_t num; char str[10]; char str2[10];} struct Struct2 { uint16_t num; char str[10];} typedef Struct1 a; typedef Struct2 b; 数据存储在文本文件中。 数据格式如下: 123 馅饼 外壳 Struct1 a存储为3个单独的参数。但是,str

我定义了几种结构,可以通过不同的操作系统(tcp网络)进行发送。 定义的结构包括:

struct Struct1 { uint32_t num; char str[10]; char str2[10];}
struct Struct2 { uint16_t num; char str[10];}   

typedef Struct1 a;
typedef Struct2 b;
数据存储在文本文件中。 数据格式如下:

  • 123
  • 馅饼
  • 外壳
Struct1 a存储为3个单独的参数。但是,struct2是两个独立的参数,第2行和第3行都存储在char str[]中。问题是,当我通过多个网络向服务器写入数据时,数据接收不正确。结构中有许多分隔不同参数的空间。当我向服务器写入时,如何确保正确的发送和填充?如何正确存储数据(动态缓冲区或固定缓冲区)

写入示例:写入(fd,&a,sizeof(typedef struct a));这是正确的吗

结构2的接收端输出有问题:

  • 123(,)
  • 0(,饼图)
  • 0(地壳,)
正确输出

123(馅饼,面包皮)

write(fd,&a,sizeof(a))不正确;至少不可移植,因为C编译器可能在元素之间引入填充以确保正确对齐
sizeof(typedef struct a)
甚至没有意义

如何发送数据取决于协议的规格。特别是,协议定义了各种各样的发送字符串的方式。通常最安全的方法是分别发送
struct
成员;通过多次调用write或
writev(2)
。例如,发送

struct { uint32_t a; uint16_t b; } foo;
在网络上,如果
foo.a
foo.b
已经具有正确的结尾,您可以执行以下操作:

struct iovec v[2];
v[0].iov_base = &foo.a;
v[0].iov_len  = sizeof(uint32_t);
v[1].iov_base = &foo.b;
v[1].iov_len  = sizeof(uint16_t);
writev(fp, v, 2);

简单的方法是为每个结构编写两个函数:一个用于将文本表示转换为结构,另一个用于将结构转换回文本。然后,您只需通过网络发送文本,并在接收端将其转换为您的结构。这样,端性就不重要了。

通过网络发送结构是很棘手的。您可能会遇到以下问题

  • 字节endiannes与整数有关
  • 编译器引入的填充
  • 字符串解析(即检测字符串边界)
  • 如果性能不是您的目标,我建议为每个要发送和接收的结构(ASN.1、XML或自定义)创建编码器和解码器。如果确实需要性能,您仍然可以使用结构并通过修复endianness(即网络字节)来解决(1) (2)修复编译器并使用pragmas或属性强制执行“压缩”结构

    例如,Gcc使用属性((压缩的)如下:

    (3) 这不容易解决。在网络协议中使用以null结尾的字符串
    而且,依赖于它们的存在,您的代码将容易受到多种攻击。如果需要使用字符串,我会使用上面建议的适当编码方法。

    有转换函数,以确保二进制整数在网络上的可移植性。使用htons、htonl、ntohs和ntohl将16位和32位整数从主机转换为网络字节顺序,反之亦然。

    您应该发布用于发送和接收的代码片段,我们真的猜不出你做错了什么。看一看它描述了如何对机器之间传输的数据进行编码。htons和htonl是你将16位和32位整数转换为网络端的朋友。ntohs和ntohl将它们转换回。@larsmans这里有一个代码片段,用于将数据读取到结构“write(sockfd,&v[0],htons(sizeof(v[0]);”结构ver1{uint16_t id;字符名[20];}v[20];//#pragma pack(0)struct ver2{uint32_t pid;char fname[20];char lname[20];}r[20];'如何将其发送(写入)到服务器?写(fd,uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。这种技术在低级别驱动程序中非常常用。
    struct mystruct {
      uint32_t  a;
      uint16_t b;
      unsigned char text[24];
    } __attribute__((__packed__));