网络字节顺序--WinSock编程

2015/05/07 计算机网络

字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;大端字节序是高字节数据存放在低地址处,低字节数据存放在高地址处。

基于X86平台的PC机是小端字节序的,而有的嵌入式平台则是大端字节序的。因而对int、uint16、uint32等多于1字节类型的数据,在这些嵌入式平台上应该变换其存储顺序。通常我们认为,在空中传输的字节的顺序即网络字节序为标准顺序,考虑到与协议的一致以及与同类其它平台产品的互通,在程序中发数据包时,将主机字节序转换为网络字节序,收数据包处将网络字节序转换为主机字节序。

无论采用的是大端顺序还是小端顺序,在网络通信中,对一台计算机所采用的字节顺序都统称为主机字节顺序。当不同字节顺序的计算机在通过网络交换数据时,如果不做任何处理,将会出现严重问题。为了解决这一问题,在编写网络程序的时候,规定发送端要发送的多字节数据必须先转换成与具体CPU无关的网络字节顺序再发送,接收端接收到数据后再将数据转换为主机字节数据。网络字节顺序采用的是大端存储方式。

1.htons函数

原型:u_short htons(u_short hostshort);

功能:该函数将一个16位的无符号短整型数据由主机字节顺序转换为网络字节顺序。

2.ntohs函数

原型:u_short ntohs(u_short netshort);

功能:该函数将一个16位的无符号短整型数据由网络字节顺序转换为主机字节顺序。

3.htonl函数

原型:u_long htonl(u_long hostlong);

功能:该函数将一个32位的无符号长整型数据由主机字节顺序转换为网络字节顺序。

4.ntohl函数

原型:u_long ntohl(u_long netlong);

功能:该函数将一个32位的无符号长整型数据由网络字节顺序转换为主机字节顺序。

程序例子:主机字节顺序到网络字节顺序转换函数的使用

#include "WinSock2.h"                 //包含WinSock库头文件
#include <iostream>
#pragma comment(lib,"ws2_32.lib")     //链接WinSock导入库

using namespace std;

int main(){
	//加载WinSock DLL
	WSADATA wsaData;
	WORD wVersionRequested=MAKEWORD(2,2);
	if(WSAStartup(wVersionRequested,&wsaData)!=0){
		cout<<"加载WinSock DLL失败!"<<endl;
		return 0;
	}

	u_short x,y=0x1234;
	x=htons(y);                      //将y值转换为网络字节顺序并将转换结果存入变量x
	cout<<"主机字节顺序:"<<hex<<y<<" "<<"网络字节顺序"<<x<<endl;

	u_long a,b=0x1122ABCD;
	a=htonl(b);                      //将b值转换为网络字节顺序并将转换结果存入变量a
	cout<<"主机字节顺序:"<<hex<<b<<" "<<"网络字节顺序"<<a<<endl;

	WSACleanup();                    //注销WinSock DLL

	system("pause");
}

针对上面4个函数,WinSock2提供了扩展形式,分别是:WSAHtons,WSANtohs,WSAHtonl,WSANtohl。以WSAHtons为例:

原型:int WSAHtons(SOCKET s,u_short hostshort,u_short * lpnetshort);

功能:该函数将一个16位的无符号短整型数据由主机字节顺序转换为网络字节顺序。

参数: s:套接字描述符 hostshort:一个待转换的主机字节顺序的16位无符号短整型数据 lpnetshort:指向一个16位无符号短整型变量指针,该指针用于存储转换后的网络字节顺序16位数据。

剩下的函数类似,以上所有函数在调用失败后返回SOCKET_ERROR,错误信息可调用WSAGetLastError()获取。

如何手算主机字节顺序转换为网络字节顺序?

假设某16位的整数,主机字节顺序的值是21,那么它的网络字节顺序是多少?

解决的步骤是:

1、将21化成二进制,二进制,如果不足16位就在其前面补0,补满16位。

21转换成二进制是:10101,在它前面补0,补满16位后就得到:

00000000#00010101

2、将这个16位二进制字符平分成两段,每段8位

0000000 000010101 == > 00000000#00010101

3、颠倒这两段的顺序,然后去掉第一个字符“1”前面的0,化成十进制就得到了网络字节顺序的值了。

00000000#00010101颠倒后:00010101#00000000

即00 01 01 01 00 000000

去掉第一个“1”前面的0得到:10 10 10 00 00 00 0 化成十进制得到:5376

如果IP地址使用的是32位的无符号整数,所以,在对IP地址进行处理的时候,就需要用到32位的转换了。例如一个点分十进制的IP地址是192.168.0.1,还原成原来的二进制原码是:    11000000 10101000 0000000 00000 0001    这是主机字符顺序存储的值。将其按照每个字节分隔开来,即每8位分隔开来,得到:

11000000 10101000 00000000 00000001    将这4段二进制编码进行完全颠倒,就得到了网络字节顺序:

00000001000000001010100011000000    去掉第一个字符“1”前面无效的0,得到:

10 00 00 00 01 01 01 00 01 10 00 00 0

化成十进制得到:16820416

Search

    Post Directory