使用htons和ntohs进行字节序转换的理解

1、示例

uint16_t   value = 0xabcd;

uchar ch[2];

memcpy(ch,&value,sizeof(uint16_t);

  • 大端,即高位在起始地址位置:

ch[0] = 0xab

ch[1] = 0xcd;

  • 小端:即低位在起始地址位置。

ch[0] = 0xcd;

ch[1] = 0xab;

2、分析

htons:是主机字节序转成网络字节序;

ntohs:是网络字节序转成主机字节序;

网络字节序是大端法排序

主机字节序,则会根据CPU、操作系统的不同而不同,可能是大端排序,也可能是小端排序

倘若,通信的两端环境完全相同,通信过程中,可以不必进行字节序转换;

但是,如果通信两端环境不同,则必须要先统一字节序,

即:

socket send端,将该主机的uint16_t,uint32_t类型数据分别使用htons,htonl转成大端排序(如果主机实际是大端,调用函数,实际上没操作,如果是小端,就给转成大端);

uint16_t   send_value = 0xabcd; 

htons(value);

保证如上例中,使报文数据流是先存  0xab,后存0xcd

socket recv端,收到的uint16_t,uint32_t类型的数据分别使用 ntohs,ntohl转成该主机对应的字节序形式(如果主机是大端,调用函数也不会转换,结果为0xabcd,如果主机是小端,使用该函数会将数据转换为小端顺序(将0xab和0xcd的顺序调换,从而保证跟send端的数据保持一致)。

uchar ch[2]={0xab,0xcd};   
uint16_t  recv_value = *(uint16_t*)ch;

如果主机是大端序,则recv_value值为0xabcd;   //与发送端的0xabcd匹配

如果主机是小端序,则recv_value值为0xcdab;   //与发送端的0xabcd,不匹配

故需要使用ntohs函数,转换成小端序,

//报文数据
uchar ch[2]={0xab,0xcd};   
uint16_t  recv_value = *(uint16_t*)ch; //值为 0xabcd 或者 0xcdab

recv_value = ntohs(recv_value); //值为 0xabcd

 除了使用:uint16_t  recv_value = *(uint16_t*)ch; 方式外,

可以使用mecpy(&recv_value,ch,sizeof(uint16_t));

小结:

使用ntohs能够保证 收到的数据跟 报文中的数据字节顺序完全一致。如上,报文中数据顺序是0xab,0xcd,使用ntohs后,

收到的一定是0xabcd.

使用htons能够保证报文中的数据字节顺序跟要发送的数据字节顺序完全一致。如上,要传的数据是0xabcd,使用htons后,报文中的一定是0xabcd.

故send,recv两边为了移植方便,两边对于uint16_t 数据都要分别添加 htons  和 ntohs;

对于uint32_t数据两边分别添加 htonl 和 ntohl

3、总结:

htons函数是固定的, 相当于将不同字节序的主机的字节序都统一成 网络字节序(大端序)

ntohs函数则是根据主机的不同,将网络字节序转换成对应主机的字节序,从而保证 send,recv 两端发送和收到的数据时一致的。

4、注意事项

因为int型数据,一个数据占多个字节,所以会产生字节序的问题,故需要调用htons,ntohs进行统一。

当数据时字符串数组,此时,报文数据就是一个字节,一个字节的存放,不存在字节的问题,也不需要调用htons,ntohs进行转换。

参考:https://blog.csdn.net/zouxinfox/article/details/1814088

你可能感兴趣的:(网络编程)