imjacob的专栏

首页博文目录订阅
正 文

网络传输数据要不要转换大小端字节序的问题?

(2009-1-4 21:29)

我看到书上讲网络时都是说:Internet上的数据以大端方式在网络上传输,所以对于内部是小端方式储存数据的机器,在internet上传输数据时就需要进行字节转换。
但是我看了一些程序,只有sockaddr_in 这个结构中sin_port ,sin_addr 这两个成员进行了转换,而没有看到传送真正的数据时进行转换,不知道这是怎么回事。今天看到一篇文章,作者也提出了这一问题,并给出了自己的解释。不知道是不是这样的。
另外,《跨平台软件开发:C & C++》这本书上也提到传输网络参数要字节转换,而不是实际的数据,但没说为什么,晕阿。

================================================================
很少有人关心字节顺序(Byte Ordering),因为它真的很少用到。何为字节顺序呢?让我们先来看一个例子,假设现在有一个WORD类型的变量,它的值为0x7788,那么它在内存中是怎么存放的呢?
内存中:

低地址 高地址

0x77 0x88

 

高地址 低地址

0x77 0x88


图3.7 两种字节顺序
事实上,对于不同的CPU、不同的操作系统,图3.7中的两种字节顺序都是可能的。如果像图3.7左边那样:高字节在前,低字节在后,则这种字节顺序称作为big-endian;如果像图3.7右边那样:低字节在前,高字节在后,则这种字节顺序称作为 little-endian。
表3.1 常见的CPU、操作系统上使用的字节顺序
CPU 操作系统 字节顺序
x86 (Intel、AMD等) 所有 little-endian
DEC Alpha 所有 little-endian
HP-PA NT little-endian
HP-PA UNIX big-endian
SUN SPARC 所有 big-endian
MIPS NT little-endian
MIPS UNIX big-endian
PowerPC NT little-endian
PowerPC 非NT big-endian
RS/6000 UNIX big-endian
Motorola m68k 所有 big-endian
一般来说,我们不用关心字节顺序问题,除非要涉及到跨平台的通信和资源共享,比如本章将要介绍的网络编程(网络传输协议TCP/IP采用的是big- endian)。假设现在要在使用不同字节顺序的机器之间传输和交换数据,那该怎么办呢?(同样的数据,不同的机器可能有不同的理解,岂不是有悖初衷!)有两种方法,一种是全部转换成文本来传输,另一种是双方都按照某一方的字节顺序来传输(这时就有一个不同字节顺序之间的相互转换问题)。

Socket编程中经常采用第二种方法。整个传输过程如下:发送端将本机的数据转换成网络的字节顺序(调用API函数htonl或htons),然后发送;接收端收到网络数据后,先将数据转换成本机的字节顺序(调用API函数ntohl或ntohs),然后再进行其它操作——如此就能保证“会议精神”在通信双方的正确传达了!这个过程中用到的几个API函数:ntohl、htonl、ntohshtons,名字都差不多,很难区分。但是如果知道了它们的来历,问题也就不存在了:n是network,网络的意思;h是host,本地主机的意思。ntohl,就是将32位的u_long类型的数据从网络字节顺序转换成本机字节顺序(htonl的字节顺序转换过程与ntohl相反);ntohs,就是将16位的u_short类型的数据从网络字节顺序转换成本机字节顺序(htons的字节顺序转换过程与ntohs相反)。

最后还有一个小问题:如何知道本机的字节顺序呢?有个很简单的方法,如下:
BOOL IsLittleEndian(void)
{
WORD wValue = 0x5678;
return (*((BYTE*)&wValue) == 0x78);
}
另外,TCPServer程序和TCPClient程序在实现时都用到了一个工具类UNetwork。这个类实现了两个静态成员函数:GetHostInfo和DumpSocketError。前者用于获取本地主机的IP地址、机器名等信息,后者用于程序调试时跟踪Socket错误。特别是DumpSocketError函数,非常实用。因为Socket程序的调试一般都比较麻烦,这时DumpSocketError函数就能将整型Socket错误码转换成容易理解的字符串说明形式输出,非常方便! 

 

但是有个问题是为什么在创建socket的时候或者bind的时候需要htons来转换字节序,而以后在send函数发送data的时候却不需要转换了呢?
我想会不会是:底层协议进行了转换,但是在创建的时候学要转换一下来“握手”,在“达成共识”以后由协议(底层程序)来完成这个工作。

http://blog.csdn.net/xiaoxiongli/archive/2007/12/20/1955877.aspx


 什么时候要进行大小端字节序的转换?

short 或者 long的数据在进行通信的时候最好养成:
1、发送的时候使用:htons(l)
2、接受的时候使用:ntohs(l)
而不要理会两边的通信是否需要这么做~~
当然了一般我都不用int型的数据通信,从来都是字符串通信,发送方利用sprintf组织,接收方利用atoi进行转换~~
评 论
3楼 52RD网友 发表于 2017-11-17 10:44 回复
当然了一般我都不用int型的数据通信,从来都是字符串通信,发送方利用sprintf组织,接收方利用atoi进行转换~~ 加密传输时,你感觉用哪个比较安全呢,所以.....
2楼 52RD网友 发表于 2010-6-3 15:35 回复
但是有个问题是为什么在创建socket的时候或者bind的时候需要htons来转换字节序,而以后在send函数发送data的时候却不需要转换了呢? send data是char时不用转,32bit和16bit的数据也是要转的。 这也是为啥socket的时候或者bind的时候需要htons来转换字节序
1楼 52RD网友 发表于 2009-10-5 09:39 回复
讲的不确切,更让人无法确定!还是一头雾水!!
博 主
进入imjacob的首页
博客名称:雅克的一府
日志总数:514
评论数量:901
访问次数:1797159
建立时间:2006-11-23 20:52
导 航
公 告
Locations of visitors to this page 本博客主要用于个人学习与资料收藏。当然大家应该读了之后也能学到不少东西。其中大多数资料都是来自网络,我转载时尽可能地表明文章出处与原作者姓名,但由于很多资料经多人转载,已不清楚原作者信息与出处,所以未表明相关…
评 论
链 接

ARM+LINUX 嵌入式博客
http://blog.chinaunix.net/u1/58780/index.html

嵌入式软件
http://blog.csdn.net/embeddedsoft

诚诚恳恳做人踏踏实实编程
http://blog.sina.com.cn/u/1244756857 

和我风格相似的一个blog
http://blogger.org.cn/blog/m…