Chinaunix首页 | 论坛 | 博客
  • 博客访问: 791955
  • 博文数量: 83
  • 博客积分: 7030
  • 博客等级: 少将
  • 技术积分: 1097
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-06 15:50
文章分类

全部博文(83)

文章存档

2011年(2)

2010年(9)

2009年(56)

2008年(16)

我的朋友

分类: LINUX

2008-04-11 11:05:43

在说明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) << 24) |

    ((n & 0xff00) << 8) |

    ((n & 0xff0000) >> 8) |

    ((n & 0xff000000) >> 24);

}

上面的代码其实很简单,就是将字节进行逆序排列。

写到这里,相信大家都对lwip处理网络序和字节序的机制有了一定的了解了。

阅读(2870) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:DTMF在VOIP中的解决方案

给主人留下些什么吧!~~