我正在尝试构建一个简单的自定义应用程序层协议,该协议本质上带有时间戳以及一些其他有用的信息,以便在不同的Linux系统之间执行少量网络测量。
就我的最初想法而言,就Linux系统而言,该实现应尽可能在不同平台(x86,ARM等)之间移植。
为了管理标题,我创建了以下结构:
FileResponse
之后,某些有效载荷数据可能存在也可能不存在(如果len = 0)。 由于此数据必须通过网络发送,因此,如果我没有记错的话,我需要打包结构,而无需任何对齐填充。
我的疑问是,实际上是否可以考虑是否已经打包(主要是由于def printPDF(request):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=hello.pdf'
p = canvas.Canvas(response)
p.drawString(100, 100, "Hello world.")
p.showPage()
p.save()
return response
来携带时间戳)。
在32位系统中,struct myhdr {
__u8 reserved; // 1 byte
__u8 ctrl; // 1 byte
__u16 id; // 2 bytes
__u16 seq; // 2 bytes
__u16 len; // 2 bytes
struct timeval sendtime; // 8 or 16 bytes
};
应该是8个字节。在64位系统下,它应该为16字节(通过打印struct timeval
进行测试)。
在32位系统下,由于1 + 1 + 2 + 2 + 2字节= 8字节(即struct timeval
的大小)是否可以安全地假定已经打包?还是在任何情况下都将添加填充以使每个字段与最后一个字段对齐(最后一个字段最大)?
在最后一个字段为16个字节的64位系统中会发生什么?我认为在任何情况下结构都不会“按布局打包”(对吗?)。
在为不同平台编译代码时,添加sizeof(struct timeval)
是否足够且始终必要,以确保结构被打包?有更好的解决方案吗?
答案 0 :(得分:4)
如果定义有线协议,则确实需要使用自己的类型。为了安全起见,即使许多32位系统仍使用32位计数器,您也应该使用1970年以来的秒数作为64位。
struct timeval
来自系统标头,基本上可以是任何大小,从8个字节开始。我确定有32位系统,其大小为12(time_t
为64位tv_sec
,以避免Y2038问题,即32位long
/ {{1 }} suseconds_t
)。此外,POSIX仅要求tv_usec
具有某些成员。某些系统在其系统头中具有显式字段,以避免编译器进行隐式填充,从而导致(假设的)打包行为出现进一步的差异。
尽管struct timeval
并不是递归适用的(因此__attribute__ ((pack))
将等于sizeof (p->sendtime)
,但它仍将包括sizeof (struct timeval)
成员在内的整个结构的对齐方式减少为1 ,因此该成员可能会错位且不适合直接与期望sendtime
的函数一起使用。