标签 Ubuntu 下的文章

又遇字节序问题

今天上午处理了一个线上产品的故障。分析来分析去,最后定位问题还是出在字节序转换的环节上。

其实测试组早在产品上线前就曾报告了这个问题,但是对应的开发人员并未对该问题进行深入地分析,而是有些草率地将该问题归结为客户端模拟器的实现不符合标准。因为这位同事比较资深,所以当时我也没有给予足够关注。

产品今天凌晨上线,9点左右业务量开始增大,这个问题立即就被我们在现场的运维人员发现,还好我们的系统是集群式的,运维同事及时的将线上有问题的版本停掉,用其他服务器支撑起了全部业务,躲过一劫。

我们还是回到这个问题上来。经验告诉我们:严重的问题往往都是由极其简单的错误导致的。这次也不例外!问题的直接原因就是:多调用了一次htonl。的确就是这么简单,但如果继续深入下去,我们还能得到一些收获。

当产品运行在x86服务器上,这个问题就会暴露出来,但是在Sun Sparc服务器上,该产品运行良好。我们分析后的结论是:这是由于在两种体系结构上htonl的实现不同而导致的。

我们先来做个试验,看下面的代码和执行结果:

/* testhtonl.c */
#include "stdio.h"
#include "arpa/inet.h"

int main() {
    unsigned int a = 0×12345678;
    unsigned int b = htonl(a);

    printf("0x%x\n", b);
    printf("0x%x\n", htonl(b));
   
    return 0;
}

将上面代码分别在x86和Sparc上编译运行。在x86上(ubuntu 10.04 Gcc 4.4.3 x86)运行的结果如下:
0×78563412
0×12345678

而在Sparc上(Solaris 10 for Sparc, Gcc 3.4.6)运行的结果如下:
0×12345678
0×12345678

由此我们可以看出,htonl这个接口并不总等价于字节序转换。在Sparc这种Big-endian体系结构的平台上,htonl相当于直接将参数值返回;而在x86这样的little-endian体系结构平台上,htonl则是等价于一个reverse_byte_order接口,每次调用都会把输入参数的byte order倒转后的结果返回。

还回到我们的那个问题中:多调了一次htonl在Sparc平台上没有什么影响;但是在x86平台上,我们得到了相反字节序的结果,导致故障的出现。

这不是我们第一次遇到字节序问题了,不过却是第一次在线上产品中遇到,上一次是在开发过程中遇到的。这次发生的问题并不仅仅是技术上的问题,更多的是在工作的严谨性和工作态度上出现问题了。对我来说,这是一个很值得吸取的教训。

使用Libtool创建库文件

除了autoconf和automake,GNU的autotools工具包中还有一种工具,它就是libtool。顾名思义,libtool是一个关于库文件制作、安装和使用的工具,它屏蔽了各个平台在库制作、安装和使用方面的差异,为上层提供了统一的接口。你可以直接使用libtool创建静态或共享库,也可以将libtool与autoconf、automake结合在一起使用。第二种方式显然更具实际意义,也更为简单。

在一个使用autoconfautomake构建的编译环境中添加libtool的支持,只需改动几处即可:
首先,你需要在configure.in(或configure.ac)中添加AC_PROG_LIBTOOL宏(注意:去掉AC_PROC_RANLIB宏)。
其次,修改Makefile.am:
如果是建立库文件,则需将lib_LIBRARIES改为lib_LTLIBRARIES,同时将库的后缀名由.a改为.la,这将告诉automake采用libtool来创建相关库:
lib_LIBRARIES = libfoo.a => lib_LTLIBRARIES = libfoo.la
libfoo_a_SOURCES = libfoo.c => libfoo_la_sources = libfoo.c

如果是使用上面生成的库文件,则将可执行程序链接的库改为.la,如:
fooapp_SOURCES = fooapp.c
fooapp_LDADD = libfoo.la

更新完上述配置后,删除aclocal.m4,执行aclocal和autoreconf,此时如果你的系统中没有安装libtool的话,autoconf会提示"undefined macro AC_PROG_LIBTOOL",安装libtool(sudo apt-get install libtool)后,错误提示消失。autoreconf会初始化libtool环境,并将libtool和ltmain.sh两个脚本拷贝到你的工程目录下。由于修改了Makefile.am,你还需要重新执行依次automake。

后面的操作大家就很熟悉了,configure -> make -> make install。libtool默认状态下会将静态库(.a)和共享库(.so)都生成出来,不过你可以通过configure命令行参数来控制这一切:
–disable-shared 不生成共享库
–disable-static 不生成静态库
–enable-shared 生成共享库
–enable-static 生成静态库

你同样可以在configure.in中控制创建的库的类型,比如,在configure.in中增加AC_DISABLE_SHARED宏就可以让libtool只创建静态库,而不生成共享库。

执行make install将库安装完后,你会发现在安装的lib目录下还保留有一份.la文件,通过该.la文件,我们可以继续通过libtool来使用这些库。当然你也可以完全略过.la而直接链接静态库(.a)和共享库(.so)。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com
这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats