2009-06-17 57 views
2

我正在创建一个协议,让两个应用程序通过TCP/IP流进行通话,并计算出如何为我的消息设计标题。使用TCP标头作为初始指南,我想知道是否需要填充。我明白,当我们处理缓存时,我们希望确保存储的数据适合缓存行,以便在检索时高效完成。然而,我不明白如何考虑应用程序解析字节流并存储它看起来合适的信息是否合理。填充或不填充 - 创建通信协议

例如:我想发送一个消息头,它由一个3字节的字段和一个1字节的填充字段组成,用于32位对齐。然后我会发送消息数据。

在这种情况下,接收器只需从流中取出3个字节并丢弃填充字节。然后开始阅读消息数据。正如我所看到的,他不会以他想要的方式存储3个字节和消息数据。整个字节对齐点是为了能够以有效的方式进行检索。但是,如果检索器不关心填充,它将如何有效地检索?

没有填充,检索器只是从流中取出3个头字节,然后取出数据字节。由于检索器存储这些字节,但他想要,填充是否完成有什么关系?

也许我错过了填充点。

从这篇文章中提取一个问题有点难,但是我说过你们可以指出我的误解。

请让我知道你们的想法。

谢谢, JBU

回答

2

如果消息体是字对齐的是一些使用的,然后通过各种手段,垫,以避免其他的扭曲该消息。如果大部分消息被处理为具有体面强度的机器字,则填充将是有益的。

如果消息是一个字节流,例如xml,那么填充不会让你成为一个好东西。就实际设计一个有线协议而言,你应该考虑使用纯文本协议和压缩(包括头文件),这可能会比你可能发明的任何手工设计的二进制协议使用更少的带宽。

+0

+1使用文本进行可读性,调试,日志记录,扩展性等和/或压缩文本以最小化尺寸;二进制格式很可能是“过早优化”。尽管如此,二进制格式*可以*优化CPU利用率和内存,这对于TCP来说是一个重要的考虑因素(并且可能对自制协议/应用程序可能不重要)。 – ChrisW 2009-06-17 02:41:32

2

我不明白如何考虑应用程序将解析字节流并存储它看起来合适的方式来填充标头是否有意义。

如果我是一个接收者,我可能会向协议驱动程序(即TCP堆栈)传递一个缓冲区(即字节数组)并说:“当它有数据时将其返回给我” 。

然后,我(应用程序)返回的是包含数据的字节数组。使用类似“铸造”等C风格的技巧,我可以将该数组的一部分视为单词和双字(而不仅仅是字节),只要它们适当对齐(即填充可能是需要)。

这里的一个语句的一个例子,其读取从一个以字节缓冲器偏移的DWORD:

DWORD getDword(const byte* buffer) 
{ 
    //we want the DWORD which starts at byte-offset 8 
    buffer += 8; 
    //dereference as if it were pointing to a DWORD 
    //(this would fail on some machines if the pointer 
    //weren't pointing to a DWORD-aligned boundary) 
    return *((DWORD*)buffer); 
} 

下面是英特尔组件中的相应的功能;请注意,这是一个操作码,即一种非常有效的方式来访问数据,更有效的阅读和积累不同的字节:

mov eax,DWORD PTR [esi+8] 
1

Oner理由认为填充是,如果你打算随着时间的推移扩展你的协议。一些填充可以有意留出,以备将来分配。

考虑填充的另一个原因是在长度字段上保存几位。即总是4的倍数,或者8在长度字段中保存2或3比特。

+1

但可能,YAGNI :) – 2009-06-17 02:27:14

1

TCP有填充(这可能不适用于你)的另一个很好的理由是它允许专用的网络处理硬件轻松地将数据从标题中分离出来。由于数据始终在32位边界上开始,所以在数据包路由时将数据头与数据分开更容易。

1

如果您有一个3字节的头并将其与4个字节对齐,那么将该未使用的字节指定为'保留以供将来使用'并且要求这些位为零(拒绝那些不是格式错误的消息)。这留下了一些可扩展性。或者您可能决定使用该字节作为版本号(最初为零),然后在对协议进行不兼容的更改(如果)时对其进行递增。不要让这个值是'未定义'和'不关心';如果你以这种方式开始,你将永远无法使用它。