网络编程-结构体网络传输

Posted by 周思进 on January 13, 2020

C编程-字节对齐(下)末尾讲到对于两方主机进行协议通信,其定义的协议结构体字段,不希望因为不同CPU可能处理字节对齐方式不同而有所差异,通过修改成1字节对齐,保证传输两方变量都是一一对应上的,这里谈到一个话题,即结构体进行网络传输,下面来说说结构体通过网络传输还存在的一些问题。

首先要了解,网络传输规定应该以大端字节序的形式进行传输,也称为网络字节序,也就是起始发送的数据是高位数据。

比如结构体中有个int类型变量,其赋值为0x12345678,对于linux而言,本地存储是小端存储,也就是起始地址放的是低位数据,即0x78存储在起始地址。如果变量数据未经大小端转换,直接进行发送,那么接收端首先接收到的数据是0x78,而网络字节序规定是大端字节序,接收端会认为0x78是高位数据,则接收转换后的值就成了0x78563412,这显然不是原始数据了。

所以对于结构体中存在多字节的变量,是需要进行网络字节序转换的。

对于long类型变量,32位系统和64位系统定义的长度不一样,所以对于传输结构体,不应该使用这样的类型变量,如果明确是8字节的,可以声明成 long long类型,如果明确是4字节的,可以声明成int类型。

不过现成的字节序转换接口只支持处理2字节或者4字节的,这个具体看网络编程-大小端问题一文,那要如何处理8字节的变量数据呢?

可以自己组装接口处理8字节数据,比如下面这样:

uint64_t htonll(uint64_t n)
{
    return ((uint64_t)htonl(n) << 32 | htonl(n >> 32));
}

uint64_t ntohll(uint64_t n)
{
    return ((uint64_t)ntohl(n) << 32 | ntohl(n >> 32));
}

但如果是浮点类型的,则建议直接转换成字符串好了,其实可以直接对整个结构体进行base64编码传输,这样就不用考虑网络传输字节序问题了。

总结下:
1、注意字节序问题
2、注意变量类型在不同系统上存在差异
3、注意结构体两边对齐方式存在差异

推荐阅读
C编程-32位和64位数据类型区别