主机字节序与网络字节序

1 主机字节序

主机字节序(host-byte)指的是处理器存储数据的字节顺序。对于Inter x86处理器来说,将数据的不重要的部分保存在低地址,重要的部分保存在高地址,即低地址中保存的是数据的低字节位,高地址保存的是数据的高字节位。

int ip_Address_hostbyte = 0x12345678;

此时,Inter x86处理器按照如图1的格式来保存变量ip_Address_hostbyte。

 

图1 ip_Address_hostbyte的保存格式

从图1中可以看出,变量ip_Address_hostbyte是按照主机字节序的方式被保存的。如果将低地址看成是“头”,主机字节序又叫做“小头”(little-endian)。

2 网络字节序

网络字节序(network-byte)指的是网络编程时,存储数据的字节顺序。与“主机字节序”相反,网络字节序将数据的重要部分保存在低地址,不重要的部分保存到高地址,即低地址保存的是数据的高字节位,高地址保存的是数据的低字节位。在网络编程时用到的IP地址和端口号都需要网络字节序。

3 转换函数

可以通过一系列的函数实现主机字节序和网络字节序之间的转换。

3.1 主机字节序转换成网络字节序

可以通过htonl()、htons()、WSAHtonl()和WSAHtons()函数实现主机字节序转换成网络字节序。函数中的h表示主机host,n表示网络networ,l表示长整形long,s表示短整形short。

3.1.1 htonl()/htons()

htonl()函数的格式为

u_long htonl(u_long hostlong);

其中,参数hostlong是主机字节序的数据,该函数的返回值是转换之后的网络字节序的数据。

int ip_Address_networkbyte = htonl(ip_Address_hostbyte);

其中,ip_Address_hostbyte是“1 主机字节序”中定义的变量。转换后的网络字节序变量ip_Address_network的数据保存格式如图2所示。

图2 ip_Address_network的保存格式

从图2中可以看出,如果将低地址看成“头”的话,网络字节序又可以叫做“大头”(big-endian)。

htons()函数的格式为

u_short htons(u_short hostshort);

该函数的用法与htonl()类似。

3.1.2 WSAHtonl()/WSANtohl()

WSAHtonl()/WSANtohl()是Winsock版本的转换函数。

WSAHtonl()函数的格式为

int WSAHtonl(SOCKET s, u_long hostLong, u_long* LpnetLong);

其中,参数s是套接字的描述符;hostLong是要转换的主机字节序的长整形;LpnetLong是指针,该指针指向的内容是转换后的网络字节序。如果转换成功,该WSAHtonl()函数返回值是0,否则返回值是SOCKET_ERROR。

在使用Winsock函数进行网络编程时,可以使用以上两个函数。

3.2 网络字节序转换成主机字节序

可以通过ntohl()、ntohs()、WSANtohl()和WSANtohs()函数实现主机字节序转换成网络字节序。使用的方法与“3.1 主机字节序转换成网络字节序”中介绍的相应的四个函数类似。

4 网络地址的赋值

SOCKADDR_IN结构用来表示网络地址和端口。

4.1 SOCKADDR_IN结构

该结构的定义为

typedef struct sockaddr_in

{

short sin_family

; ADDRESS_FAMILY sin_family

; USHORT sin_port

; IN_ADDR sin_addr

; CHAR sin_zero[8];

}SOCKADDR_IN, *PSOCKADDR_IN;

其中,sin_family表示地址族;sin_port是通信的端口号,该端口号是网络字节序;sin_addr是IN_ADDR结构的对象,表示IP地址,该IP地址也是网络字节序;sin_zero是字符数组,为了使得SOCKADDR_IN结构与SOCKADDR的结构的大小相同,用sin_zero来作为SOCKADDR_IN结构的填充。

4.2 IN_ADDR结构

在“4.1 SOCKADDR_IN结构”中提到了该结构的成员变量sin_addr是IN_ADDR结构的对象。IN_ADDR结构的定义为

typedef struct in_addr {

  union {

    struct {

      UCHAR s_b1;

      UCHAR s_b2;

      UCHAR s_b3;

      UCHAR s_b4;

    } S_un_b;

    struct {

      USHORT s_w1;

      USHORT s_w2;

    } S_un_w;

    ULONG  S_addr;

  } S_un;

} IN_ADDR, *PIN_ADDR, *LPIN_ADDR;

从ADDR_IN结构的定义可以看出,该结构是一个union,包含了IP地址的三种表达方式。其中S_un_b的四个成员变量分别表示点格式IP地址的四个部分;S_un_w的两个成员变量分别表示IP地址的高字部分和低字部分;S_addr是IP地址的无符号长整形格式。

4.3 代码实现

SOCKADDR_IN addr;

addr.sin_family = AF_INET;

inet_pton(AF_INET, "192.168.1.1", &addr.sin_addr.S_un.S_addr);

addr.sin_port = htons(12345);

AF_INET表示使用的IP族;inet_pton()函数的作用是将点格式的IP地址转换为数字,该函数的第3个参数是SOCKADDR_IN结构的S_addr,即无符号长整形,inet_pton()函数的使用方法请参考《VS2015中IP地址转换函数》;通过htons()函数将主机字节序的端口转换为网络字节序,并将其保存在SOCKADDR_IN结构的sin_port中。图3是addr.sin_port的值。

图3 addr.sin_port的值

因为12345的主机字节序是0x3039,所以其网络字节序是0x3930。

相关链接:使用inet_pton()函数将IP地址格式进行转换时,还可以使用如下代码

inet_pton(AF_INET, "192.168.1.1", &addr.sin_addr.s_addr);

因为在inaddr.h中对s_addr进行了定义

#define s_addr  S_un.S_addr /* can be used for most tcp & ip code */

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值