免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1078 | 回复: 0
打印 上一主题 下一主题

lwip中转换主机序和网络序的代码分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-04-11 11:05 |只看该作者 |倒序浏览

在说明lwip中如何进行主机序和网络序的转换时,我们有必要先了解几个基本概念:MSB、LSB、Big Endian、Little Endian、网络序和主机序。
MSB是Most Significant Bit/Byte的首字母缩写,通常译为最重要的位或者最重要的字节;那么对于一个数字而言,什么是MSB呢?显然最高位是MSB,例如15430,1就是MSB,因为它在万位,它的变化是以10000为基数的。知道了MSB,LSB也就不难理解;LSB是Least Significant Bit/Byte的首字母缩写,通常译为最不重要的位或者最不重要的字节;对于15430而言,0显然是LSB,因为它在各位,它的变化对于整个数值的大小影响最小。
Big Endian和Little Endian是描述排列存储在计算机内存里的字节序列的术语。之所以出现两种排列次序,是由于CPU的两大对立阵营的对抗导致的,PowerPC(Moto&IBM) VS X86 = Big Vs. Little。在Big Endian机制中最重要字节(MSB)存放在最低端的地址上;而Little Endian机制中,最不重要字节(LSB)存放在最低端的地址上。
例如0x12345678在采用Big Endian的CPU(PowerPC为代表)中,其存放顺序为:
0x0000
12
0x0001
34
0x0002
56
0x0003
78
图1 0x12345678在Big Endian CPU中的存储方式
而在采用Little Endian的CPU(X86为代表)中,其存放顺序为:
0x0000
78
0x0001
56
0x0002
34
0x0003
12
图2 0x12345678在Little Endian CPU中的存储方式
关于Big Endian和Little Endian还有一点需要说明的是:软件只需要关注字节顺序就可以了,硬件除了要处理字节顺序外,还需要处理位序。如果你觉得Big Endian和Little Endian很难理解,可以这么理解,Big Endian就是最先读出最高(最大)的字节,而Little Endian最先读出最低(最小)的字节。
通常在TCP/IP协议栈所说的网络序(Network Order)就是遵循Big-Endian规则。在TCP/IP网络通信中,通信双方把消息按照如图1的方式进行编码,然后按从MSB(Bit0)到LSB的顺序在网络上传送;而通常我们说的主机序(Host Order)(X86架构CPU)就是遵循Little-Endian规则。所以当两台主机之间要通过TCP/IP协议进行通信的时候就需要调用相应的函数进行主机序(Little-Endian)和网络序(Big-Endian)的转换。
了解了这些基本概念后,我们进入正题。lwip由于考虑到移植性问题,因此它没有默认主机序为Little Endian,而是两种情况都进行了处理;而且处于灵活性考虑,还允许我们用自己定义的代码替换lwip提供的函数:
#if LWIP_PLATFORM_BYTESWAP
   #define htons(x) LWIP_PLATFORM_HTONS(x)
   #define ntohs(x) LWIP_PLATFORM_HTONS(x)
   #define htonl(x) LWIP_PLATFORM_HTONL(x)
   #define ntohl(x) LWIP_PLATFORM_HTONL(x)
#else
   u16_t htons(u16_t x);
   u16_t ntohs(u16_t x);
   u32_t htonl(u32_t x);
   u32_t ntohl(u32_t x);
#endif
如果我们需要采用自己定义的函数,只需要定义LWIP_PLATFORM_BYTESWAP为1,并编写相应的函数即可:
#define LWIP_PLATFORM_BYTESWAP 1
#define LWIP_PLATFORM_HTONS(x)
#define LWIP_PLATFORM_HTONL(x)
考察了lwip实现的灵活性后,我们再来看看其移植性问题。为了便于移植,lwip引入了3个宏:BYTE_ORDER、LITTLE_ENDIAN和BIG_ENDIAN,后两个宏的定义为:
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN 1234
#endif
#ifndef BIG_ENDIAN
#define BIG_ENDIAN 4321
#endif而BYTE_ORDER由我们自己根据CPU类型来定义,如果CPU采用Big Endian,就定义为4321,反之就定义为1234。
有了这三个宏以后,代码的编写就很简单了:
#if BYTE_ORDER == BIG_ENDIAN
#define htons(x) (x)
#define ntohs(x) (x)
#define htonl(x) (x)
#define ntohl(x) (x)
#else /* BYTE_ORDER != BIG_ENDIAN */
#if LWIP_PLATFORM_BYTESWAP
#define htons(x) LWIP_PLATFORM_HTONS(x)
#define ntohs(x) LWIP_PLATFORM_HTONS(x)
#define htonl(x) LWIP_PLATFORM_HTONL(x)
#define ntohl(x) LWIP_PLATFORM_HTONL(x)
#else
u16_t htons(u16_t x);
u16_t ntohs(u16_t x);
u32_t htonl(u32_t x);
u32_t ntohl(u32_t x);
#endif
当CPU类型为Big Endian时,主机序与网络序同序,不需要改动;而CPU类型为Little Endian时,主机序与网络序正好相反,此时lwip定义了相应的函数来处理,这些函数通过移位来实现,本文以u32_t htonl(u32_t x)来说明:
u32_t
htonl(u32_t n)
{
  return ((n & 0xff)     ((n & 0xff00)     ((n & 0xff0000) >> 8) |
    ((n & 0xff000000) >> 24);
}
上面的代码其实很简单,就是将字节进行逆序排列。
写到这里,相信大家都对lwip处理网络序和字节序的机制有了一定的了解了。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/45185/showart_526701.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP