关于vc++里面htonl()函数的使用疑惑

#include<iostream.h>#include<winsock2.h>voidmain(){structsockaddr_inmyad;memset(&myad... #include <iostream.h>
#include <winsock2.h>

void main()
{
struct sockaddr_in myad;
memset(&myad,0,sizeof(struct sockaddr_in));
myad.sin_family=AF_INET;
myad.sin_port=htons(4367);
myad.sin_addr.s_addr=htonl(0x40);

cout<<myad.sin_addr.s_addr<<endl;
}

myad.sin_addr.s_addr=htonl(0x40)时 输出的结果转换成16进制是40000000
myad.sin_addr.s_addr=htonl(0x4000)时 输出的结果转换成16进制是400000
myad.sin_addr.s_addr=htonl(0x400000)时 输出的结果转换成16进制是4000
myad.sin_addr.s_addr=htonl(0x40000000)时 输出的结果转换成16进制是40

求解释htonl函数在这个程序中的工作过程和原理 谢谢!
展开
 我来答
mayadong7349
2011-02-22 · TA获得超过2356个赞
知道大有可为答主
回答量:362
采纳率:0%
帮助的人:669万
展开全部
htonl就是把本机字节顺序转化为网络字节顺序
所谓网络字节顺序(大尾顺序)就是指一个数在内存中存储的时候“高对低,低对高”(即一个数的高位字节存放于低地址单元,低位字节存放在高地址单元中)。但是计算机的内存存储数据时有可能是大尾顺序或者小尾顺序。
先举个例子:
int a = 0x403214;
int b = htonl(a);
我在VC++6.0调试这段代码,发现
&a的值为:0x0012ff44
其中0x0012ff44、0x0012ff45、0x0012ff46、0x0012ff47这四个单元的值依次为:14、32、40、00,即0x403214这个数的高位部分存放在高位地址中,低位部分存放在低位地址中,即小尾顺序。
&b的值为:0x0012ff40
其中0x0012ff40、0x0012ff41、0x0012ff42、0x0012ff43这四个单元的值依次为:00、40、32、14,即把原数0x403214的高位部分存放在低位地址中,低位部分存放在高位地址中。
由此可见,如果一个数以小尾顺序存储,经htonl函数调用后这个数的高地位字节会完全颠倒过来成为一个新的数。这个新的数在机器内部其实还是以小尾顺序存储的,但是相对于原来的数而言相当于是变成大尾顺序的了。
long型的0x40写完整为:0x 00 00 00 40,共四个字节,调用htonl后四个字节颠倒顺序,为0x 40 00 00 00。
同样,0x40 00 00 00调用htonl后变为0x 00 00 00 40,即0x40
如果我的回答有问题,可以HI我,我们接着讨论
崭天
2011-02-22 · 超过15用户采纳过TA的回答
知道答主
回答量:40
采纳率:100%
帮助的人:16.5万
展开全部
主机字节顺序转化为网络字节顺序的函数,且转化的单位是无符号长整形。占4个字节。
更具体的说,就是小尾存储的字节顺序转化为大尾存储的字节顺序。
其实就是按照字节,前后顺序置换。

简单的说:
0x40 ===>00000000 00000000 00000000 01000000
前后顺序置换之后,
就是01000000 00000000 00000000 00000000 =》即 0X40000000
0x4000 ===>00000000 00000000 01000000 00000000
转化:
00000000 01000000 00000000 00000000
即 0x400000
其它类推。。
0x400000 =>0x4000
0x40000000 =>0x40

不知道这么说来,楼主朋友是否清楚了呢?
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
6059lgvjl6
2011-02-22 · TA获得超过1287个赞
知道小有建树答主
回答量:773
采纳率:0%
帮助的人:159万
展开全部
关键是recvfrom返回的客户端addrClient是不能作为服务器返回客户端的地址使用的,即在sendto中不能使用由recvfrom返回得到的客户端地址。

楼主将UDP通讯和TCP通讯搞混了,不过说实话这个是很正常的。当初我学的时候没一本书是把网络通信编程写清楚地,只能靠自己摸索。

socket可以理解为通信地址,它由协议,IP和端口组成。在UDP模式中,绑定的目的是要告诉操作系统,当网卡从外部接收到数据包时,操作系统就知道应该把这个数据包交给哪个应用程序。
具体是这样的,网卡总是知道自己的IP是什么,因此网卡接收到网线中的数据包时,会提取数据包的包头,里面含有的IP如果是网卡自己的IP,它就会把该数据包交给操作系统,如果不是就将该数据包丢弃,可以认为操作系统不知道有该数据包。操作系统接收到数据包后,会根据每个数据包包含的端口号,将该数据包发给不同的应用程序。操作系统怎么会知道哪个端口号对应哪个应用程序呢?这个就是要求应用程序使用bind函数,将自己的端口号告诉操作系统。因此,所谓的端口冲突就是指其他应用程序已经通过bind告诉了操作系统该端口被它使用了,因此另外的应用程序就不能使用该端口了,即bind肯定失败!
所以,bind肯定是由接受数据包的应用程序使用的,这样的应用程序就是服务器应用程序,也可以看到我们需要为bind提供IP和端口号。并且,当初我还在疑惑为什么会有一个INADDR_ANY的IP指定,似乎bind根本不需要IP啊,只要端口就可以了。仔细一想才明白,因为一台主机可能会有2个网卡。因此,主机可能会有两个IP,这样bind这个函数允许我们自由指定需要绑定到哪块网卡上的特定端口。也可以不指定,通过INADDR_ANY由操作系统为我们指定。譬如,13端口在第一块网卡中被占用了,我们就可以使用bind明确指定自己的应用程序接收来自第二块网卡13端口的数据包。

UDP编程中作为客户端发送数据时,是不需要指定自己的IP和端口的,因此无需使用bind绑定,直接在sendto指定服务器的IP和端口就可以了。但实际上发送数据时,操作系统还是需要使用客户端机器上的一个IP和端口号的,这个IP和端口号由操作系统指派,譬如在操作系统处理sendto时,它可以指派1005端口给UDP客户端,此时如果有另一个客户程序再使用bind注册该端口,就会失败了。但实际情况大家都知道,UDP数据包的发送是相当快的,这种冲突几乎不存在,因为数据包发送后,即数据包通过网卡发到了网线中,操作系统就认为发送成功了,该端口就会被操作系统收回,标记“未使用”。

总结一下,UDP服务器需要占用一个IP和一个端口号,且是固定的,是在调用了bind函数成功后便确定下来了。UDP客户端也需要使用一个IP和一个端口号,它们都是随机的,这次发送可能是第一块网卡,第二次可能是第二块网卡,端口也如此。发送后,该端口就被操作系统收回,因此客户端无法使用该端口接收来自服务器的数据包。

因此不能使用recvfrom的客户端的端口信息再调用sendto发送给客户端,因为客户端的电脑操作系统根本不会讲该数据包交给客户端应用程序。

以上用比较容易理解的概念介绍了下,其实精确说的话,很多事情不是操作系统做的,而是各种驱动程序完成的。具体怎么修改代码,楼主应该明白了吧,光改服务器端的代码,没用,客户端的代码也要改。这也是为什么UDP是不存在服务器,客户端之说的原因,因为任何一方给另一方发数据包,前提必须使另一方已经通过bind绑定了一个固定端口了。
追问
哥 你回答的这是啥。。。?

参考资料: 百度一下

已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(1)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式