htonl,htons 和 ntohs相关问题

htonl函数是一个网络转换的函数,他把不确定的一个32位数字,转换成网络通用的32位数字,即大头在后的方式。

我们一般使用的计算机都是大头在后,也就是高地址在后面的形式。
比如你定义一个整型变量
int i = 0x12345678
然后在定义一个整型指针
int *p = &i;

假设p的地址是0x0012f2ec
那么在这个地址后4个字节都是这个整数,他的存放形式为


如果是大头前,也就是高地址在前,则存放形式为
0x0012f2ec:12 34 56 78

使用htonl函数后,他的存放形式就便为
0x0012f2ec:78 56 34 12


需要根据操作系统的不同确定你是否需要使用。

****************************************************************************

htonl = Host To Network, type Long
ntohl = Network To Host, type Long
同理,还有 htons 和 ntohs,这里的 s 是指 short

/***************************************************************************/

x86系统的数据存放都是按照little-endian的格式(硬件层没有对字节序的区分机制)。
通过对Windows平台的字节序转换函数(htons/ntohs(16bit),htonl /ntohl(32bit))的代码的分析,发现Windows对这样的转换没有进行特别的字节序检测,仅仅简单的进行了高低位的转换。

至于为什么没有做检测。我的理解是些转换函数已经默认了参数的字节序(MSDN)。
对于htons,htonl的参数为host byte order(小头);
对于ntohs,ntohl的参数为network byte order(大头)

其实,在调用函数时,我们就隐含指定了数值(注意,可能并非我们定义的数值)。
上面的程序中,可以这样理解。
d = htonl(c);
将小头存放(78’56’34’12)的数值0x12345678 转换为大头存放(12’34’56’78),并附给d。
注意:虽然这时d在小头系统中为0x78563412,但真实的数值是大头序的0x12345678。
e = ntohl(c);
将大头存放(78’56’34’12)的数值0x78563412 转换为小头存放(12’34’56’78),并附给e。

综上所述,导致这个疑问有以下几点。
1.字节序转换函数默认了被转换参数的字节序,所以没有必要再进行检测。
2.对转换后的数值的误解。(d的数值应为0x12345678,而非0x78563412)
3.调用ntohl函数时,对于参数的指定存在误解。
e = ntohl(0x78563412); /*数值0x12345678应该这样指定*/


对于htonl /ntohl代码一样的问题,属x86系统的特例。
如果,有这样一种字节序系统1’3’4’2,对于数值0x12345678的保存形式应该是12’56’78’34。
这个系统上的htonl /ntohl関数的实现应该不会一样的。
也许DiabloWalkOnTheEarth(WorldOfWg( 狗城是个烂代理 )) 所说的机器就是这么一种“非little/big-endian”的字节序,呵呵。


To 0delphi(睡个舒服觉)

的确判别一个 系统 是大头序还是小头序的方法是有的。
比如:
-BEGIN-
int x=1; // 0x00000001
if (*(char*)&x) {
/* little endian. memory image 01 00 00 00 */
}else{
/* big endian. memory image 00 00 00 01 */
}
-END-
内存数据(0x00000001)-〉大头/小头字符序-〉数值(1)
这里判别的前提条件是知道内存数据及所对应的数值,所以可以判定出大小头字符序。  
/*************************************************************************************************************/

字节顺序
不同的计算机处理数字有两种形式,big-endian和little-endian型式(
little-endian格式的数据,例如0X12345678以(0X78 0X56 0X34 0X12)方式保存、
big-endian格式的数据,例如0X12345678以(0X12 0X34 0X56 0X78)方式保存 ),这依赖于他们是怎么设计的,比如Intel的x86处理器,多字节是用little-endian型式。IP地址和和端口在电脑中是多字节存放的,他们是host-byte顺序,然而当IP地址和端口通过网络时,必须转成big-endian形式,也就是network-byte顺序
  有一系列函数完成两者之间的转换。比如
host-byte序转network-byte序
u_long htonl(u_long hostlong);
int WSAHtonl( SOCKET s, u_long hostlong, u_long FAR * lpnetlong );
u_short htons(u_short hostshort);
int WSAHtons( SOCKET s, u_short hostshort, u_short FAR * lpnetshort );

network-byte序转host-byte序
u_long ntohl(u_long netlong);
int WSANtohl( SOCKET s, u_long netlong, u_long FAR * lphostlong );
u_short ntohs(u_short netshort);
int WSANtohs( SOCKET s, u_short netshort, u_short FAR * lphostshort );    
 
========================================================
inet_ntoa  :将一个IP转换成一个互联网标准点分格式的字符串。
 
原型:
char FAR * inet_ntoa( struct in_addr in);
头文件:
arpa/inet.h
Winsock2.h
参数:
一个网络上的IP地址
返回值:
如果正确,返回一个字符 指针,指向一块存储着点分格式IP地址的静态缓冲区(同一线程内共享此内存);错误,返回NULL。
 
基本要求
操作系统:Windows 2000 Professional 或更高版本
头文件:Winsock2.h
链接库:Ws2_32.lib
 
实例:
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
char recvBuf[100];
char tempBuf[100];
sprintf(tempBuf,"%s say: %s",inet_ntoa(addrSrv.sin_addr),recvBuf);
//将sin_addr储存的IP(127.0.0.1)转换成字符串形式
 
 
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值