网络编程中经常会涉及到二进制数据传输的问题,在C++中常用的传输方式有文本字符串和结构体封包。如果能将要发送的数据事先放进连续的内存区,然后让send函数获取这片连续内存区的首地址就可以完成数据的发送了,文本字符串如char型数组,以字节为单位,在内存中是顺序存储的,所以可以直接用send函数发送。但是如果要同时发送多个不同类型的数据时,它们在内存中存储的地址是随机的,不是顺序存储的,而且它们之间的相对位置也无法确定,这样就需要一种数据组织方式来明确各数据之间的相对位置。结构体显然就是一种的数据组织方式,使用结构体要注意数据对齐的问题,关于结构体中数据对齐的问题可参考这篇文章:http://blog.163.com/kan586@126/blog/static/95532454200891191451827/
如果熟悉结构体中数据对齐的规则,可以合理设计结构体的结构,各成员变量的顺序,使得所有的数据成员存放在连续的存储区,而且结构体的长度等于所有成员长度之和(可以适当在尾部用字符数组补齐,避免编译器自动填充),这样就方便用send函数发送了。( 如果服务器和客户端都是用C/C++开发,两端可以通过同样结构的结构体来封包和解包,可以不考虑数据对齐的问题)下面讨论的是在C++和python开发的两端之间传输数据的情况:客户端用的C++编写,服务器端用python编写,相对于C++中用struct来封包和解包,python提供了struct库实现类似的功能,最重要的三个函数是pack,unpack,calcsize,struct库处理二进制数据的具体用法可以参考这篇文章:http://www.cnblogs.com/gala/archive/2011/09/22/2184801.html。在python下用socket接收到的字节流实际上是字符串,需要对所有的字节进行指定解析格式,所以在C++发送的时候就要避免发送不确定的数据(如编译器自动填充的数据),如果用struct组织数据就需要考虑数据对齐的问题了。下面用一个实例来说明:在C++客户端有1个a(float) ,1个b(unsigned char),一个c(short) 要发送给服务器端,在不使用#pragma指令指定编译器的对齐位数时, 在我的编译器环境下默认为4,可以这样设计结构体:
struct data
{
float a; //0~3
short c; //4~5
unsigned char b; //6
char extra[2]; //7~8 结构体长度为8字节,这里用字符数组补齐8字节,避免编译器填充
};
python服务器端用struct库来解包,可以设计如下格式:
import struct
...
rdata = s.recv(1024)
a,b,c,d = struct.('fhB2s',rdata) #a,b,c即是需要的数据
print a,b,c