网络编程字节序转换问题

一:大小端

(一)大小端区别(字节)

区别是依据:计算机系统在存储数据时起始地址是高地址还是低地址

小端:从低地址开始存储

大端:从高地址开始存储

补充:这里大小端是按字节区别的,还有按字的。按字节,则字节大小数据不会改变数据格式,所以如上图中小端“1”,和大端“1”是一样存储的

补充:在内存中存储数据还是从低地址开始寻址,找到一块空间分配以后,根据大小端区别向内部填充数据

(二)代码实现对大小端的判断

#include <iostream>
#include <stdint.h>

using namespace std;

bool bigCheck()
{
    union Check{ //起始地址是一致的
        char a;
        uint32_t data;
    };
    Check c;
    c.data = 1;
    if(1==c.a){
        return false;
    }
    return true;
}

int main(int argc,char* argv[])
{
    if(bigCheck()){
        cout<<"big "<<endl;
    }else{
        cout<<"small "<<endl;
    }
    return 0;
}

1.选取内存空间

2.大端存放数据

3.小端存放数据

输出结果:

二:本地系统与网络中的大小端问题

(一)本地操作系统与网络字节序

1.本地字节序

不同操作系统可能会采用不同的字节序,所以当通信双方字节序不同时需要考虑字节序转化问题

2.网络字节序

为了避免在网络通信中引入其他复杂性,网络字节序统一是大端的

(二)序列化与反序列化

任何变量,不管是堆变量还是栈变量都对应着操作系统中的一块内存,由于内存对齐的要求程序中的变量并不是紧凑存储的,例如一个c语言的结构体Test在内存中的布局可能如下图所示。

1.序列化:通过将计算机语言中的内存对象转换为网络字节流,例如把c语言中的结构体Test转化成uint8_t data[6]字节流。

2.反序列化:将网络字节流转换为计算机语言中的内存对象,例如把uint8_t data[6]字节流转化成c语言中的结构体Test。

通过序列化可以使得网络传输得到数据量更少,通过反序列化使得数据接受时格式与原来一致。

三:网络编程中的一点小疑惑

(一)前面提到本地字节序和网络字节序(大小端)不同,那么如何转换??

htonl()--"Host to Network Long"
ntohl()--"Network to Host Long"
htons()--"Host to Network Short"
ntohs()--"Network to Host Short"  

以上4种函数实现了对16位、32位数据的网络到本地、本地到网络的转换。

补充:数字所占位数小于或等于一个字节(8 bits)时,不要用htons转换。这是因为对于主机来说,大小端的最小单位为字节(byte)

(二)本地到网络中的哪些数据需要转换??(重点)

不是所有从本地传输到网络中的数据都需要进行大小端的转换!!!

我们只需要将IP网络层需要访问的数据转化为大端模式,这样网络才知道如何传递、转发数据。而这些数据是指IP地址和端口,IP网络层需要根据这些信息进行转发。

IP为网络层,使用的是大端字节序,在IP层中要读取TCP头部中的信息,以确定要访问的地址。

所以要将port,ip等将在网络层被读取的信息转为大端字节序。

而发送的具体信息,并不被网络层所读取(只是传输),因此只要保证接受方与发送发使用的字节序相同,就不需要进行转换

posted @ 2020-11-20 17:00  山上有风景  阅读(801)  评论(0编辑  收藏  举报