通信协议与字节序问题

通信协议与字节序问题

传统的通信协议通常采用字节序进行定义,与现代的VOIP协议采用文本方式定义截然相反。采用字节序方式的优点是效率高、节省空间,但是也引入了很多的问题,其中最普遍的就是big endian和little endian的问题。

x86CPU采用little endian字节序,而power系列采用big endian字节序。little endian是低地址存放最低有效字节,而big endian是指低地址存放最高有效地址。通常又把big endian称为网络字节序。
big endian比较符合人类的思维习惯,例如数字0x12345678在CPU中的存储顺序如下:

Big Endian

低地址                                             高地址
—————————————–>
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      12      |       34     |      56       |      78     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Little Endian

低地址                                             高地址
—————————————–>
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      78      |       56     |      34       |      12     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

在通信协议中,往往采用Big endian定义。

在通信协议设计时,位域的定义也有这个顺序的问题。另外,对16/32位整数,也需要注意进行主机字节序和网络字节序的转换。

下面以RTP协议的一个定义为例:

相应的C代码定义为:
struct RTPHeader
{
#ifdef RTP_BIG_ENDIAN
uint8_t version:2;
uint8_t padding:1;
uint8_t extension:1;
uint8_t csrccount:4;
uint8_t marker:1;

uint8_t payloadtype:7;

#else // little endian
uint8_t csrccount:4;
uint8_t extension:1;
uint8_t padding:1;
uint8_t version:2;

uint8_t payloadtype:7;
uint8_t marker:1;
#endif // RTP_BIG_ENDIAN

uint16_t sequencenumber;
uint32_t timestamp;
uint32_t ssrc;
};

其中,sequencenumber,timestamp,ssrc在发送和接收时,需做字节序转换。C语言中,常用函数为:htons,htonl,ntohl,ntohs。

Comments are closed.