Linux网络编程 之 大小端初探

13 篇文章 0 订阅
1 篇文章 0 订阅

    首先解释一下大小端的概念。

    大端(Big Endian),同时也是网络序,是数据在网络上传输的一种数据组织格式,其存储的方式比较符合人们读写的习惯。

    小端(Little Endian),这里不能说其是主机序,因为主机可能采用的是大端cpu也可能采用的是小端cpu,小端与大端相对。

    通过一个例子深入了解它们之间的区别:

    用一台Big Endian 和 另一台 Little Endian 分别存储32bit的数值,为:0x12345678,数据在内存当中的存储顺序如下表所示。

Addr

Big Endian

Little Endian

0xa

0x12

0x78

0xb

0x34

0x56

0xc

0x56

0x34

0xd

0x78

0x12

 

    由表1可以清晰看到,在大端计算机当中,存储方式可以总结为八个字:大端(高字节)存在起始地址;在小端计算机当中,可以总结为八个字:小端(低字节)存在起始地址我们深入了解字节在计算机当中的存储方式,仍以0x12345678为例。

    32 bit representation in memory:

  • Big Endian:

    Hex: 0x12345678

    Binary: 00010010 00110100 01010110 01111000

  • Little Endian

    Hex: 0x78563412

    Binary: 01111000 01010110 00110100 00010010

    Decimal: ‭305419896‬

    从上面的数据分布,可以发现一个规律,不论大小端,他们存储字节,字节当中的bit位相对顺序一样的,由此,给我们大小端互相转换提供了思路,利用位运算和移位运算。实际上linux已经为我们提供了字节序转换的api,我们可以在linux终端下令入:man htonl 即可查看到使用此函数所需要包含的头文件,用法等,键入后得到结果如下图所示:

    

    现在我们去找一下htonl 的linux实现代码,由于linux的头文件基本都在/usr/include下,因此我们直接利用linux提供的find工具去进行搜索:在终端键入

    find /usr/include/ -type f | xargs grep -n htonl

    得到结果如下:

红色的两句对我们而言是比较有用的两句,从上面可以看到,htonl其实是__int32_identify 和 __bsway_32的宏替换,我们键入命令打开文件 /usr/include/netinet/in.h查看并定位到行397(vim 下键入":"并输入行号即可定位到相应行)。

vim /usr/include/netinet/in.h

得到如下结果:

得知一个是用于大端的转换(其实大端已经没有必要转,网络流进主机的数据,就是大端的)我们可以猜想,这个__int32_identify是一个类似 #define__int32_identify(x) x空的宏定义或者一个直接将传入参数返回的函数,事实证明ubuntu中采用的的是后者,并且使用了内连函数。我们继续查找__bsway_32,因为这个函数的实现才是我们所关心的,在终端键入:

find /usr/include/ -type f | xargs grep -n __bswap_32

得到如下结果:

红色框起来的部分信息就是我们所寻找的信息,打开文件byteswap.h并定位到45行

vim /usr/include/x86_64-linux-gnu/bits/byteswap.h

从代码当中可以看到,针对不同的编译器版本,提供了不同的字节转换,有使用编译器内建的函数,也有使用汇编实现的字节序的转换,同时也有代码自己实现的__bswap_constant_32(x),这也正是我们所关注的,可以看到,这个宏定义的实现,正是采用移位运算和位运算完成字节序的转换。

#define __bswap_constant_32(x) \

((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \

(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))

我们分析一下这个宏定义,例如小端上存储的为0x78563412,由上面的分析得知网路序其实是0x12345678,我们用这个函数证实一下:

0x78563412 & 0xff000000 值为 0x78000000 ,左移24bit即 0x00000078

0x78563412 & 0x00ff0000 值为 0x00560000 ,左移 8bit 即 0x00005600

0x78563412 & 0x0000ff00 值为 0x00003400 ,右移 8bit 即 0x00340000

0x78563412 & 0x000000ff 值为 0x00000012 ,右移24bit即 0x12000000

最后将右侧的结果按位与得到结果0x12345678,结果符合我们的猜想。

从网络序转换为主机序的分析思路与此完全一致,有兴趣的盆友可自行动手试探一番。

好啦,字节序转换初步写到这里,这里仅仅介绍了字节间的转换,并没有分析跨字节位域怎么储存和我们怎么转换和存值,欲知后事,请听下回分析~

 

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值