在C中,通过具有正确填充和结尾的套接字发送结构
我定义了几种结构,可以通过不同的操作系统(tcp网络)进行发送。 定义的结构包括:在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
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
- 馅饼
- 外壳
- 123(,)
- 0(,饼图)
- 0(地壳,)
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__));