有时候我们需要在不同体系架构间通过网络传递数据,典型的有两类:一是程序自己定义的data struct, 另一个是应用数据,比如传输一个文件的内容。在我们的场景里,这两类数据都需要在AIX(PPC)和Linux(x86)之间传递。这种情况将不可避免涉及所谓byte order的big-endian和little-endian之间的转换问题。如果你只在一台机器上倒腾数据,那么big还是little根本就不会成为问题,但是对于设备驱动程序而言,需要关注CPU与外设之间对内存数据的解释问题。

1. 程序自定义的数据结构
   x86上的Linux作为server, 通过socket方式传递一个data struct:

点击(此处)折叠或打开

  1. struct le_data{
  2.         uint32_t a;
  3.         uint32_t b;
  4.         uint32_t c;
  5. }__attribute__ ((packed));
Linux server上主要的代码片段如下:

点击(此处)折叠或打开


  1. int main(void)
  2. {
  3.      struct le_data le_dbuf;
  4.      int lisfd, connfd;

  5.      le_dbuf.a = 10;
  6.      le_dbuf.b = 20;
  7.      le_dbuf.c = 30;
  8.      ...
  9.      wrn = write(connfd, &le_dbuf, sizeof(le_dbuf));
  10.      ...
  11. }

AIX client如果需要通过socket得到正确的结构体中的变量b(=20),则必须做字节转换,否则将得到错误的数值,主要代码片段如下:

点击(此处)折叠或打开

  1. struct le_data{
  2.         uint32_t a;
  3.         uint32_t b;
  4.         uint32_t c;
  5. }__attribute__ ((packed));

  6. inline uint32_t SwapEndian(uint32_t val)
  7. {
  8.         val = (val<<24) | ((val<<8) & 0x00ff0000) |
  9.                   ((val>>8) & 0x0000ff00) | (val>>24);
  10.         return val;
  11. }

  12. int main(void)
  13. {
  14.       struct le_data ldata;
  15.       ...
  16.       err = read(fd, (char *)&ldata, sizeof(ldata));
  17.       printf("sizeof(ldata) = %lu, ldata.b = %u\n", sizeof(ldata), SwapEndian(ldata.b));
  18.       ...
  19. }
在上面的代码中,如果将19行改成:
printf("sizeof(ldata) = %lu, ldata.b = %u\n", sizeof(ldata), ldata.b);
将会得到错误的结果,而不是20. 简单用下图解释一下上述结果(此处假设在x86机器上ldata.a =0x01020304, ldata.b=0x05060708):

通过socket在PPC和x86之间传递数据结构和应用数据-LMLPHP
图中左图是通过socket传输前的结构体对象ldata在x86机器内存中的layout,这段内存通过socket传输到PowerPC机器上后,在后者的内存空间中的layout是不变的,如右图所示。对结构体成员变量的解释属于编译器的范畴,所以x86上的ldata.a与PPC上的ldata.a的语义是相同的,但是对于处理器来讲,big与small对内存的解释不同,换言之,同样的ldata.a内存区,x86上处理器认为是0x01020304,而在PPC看来则是0x04030201,所以需要通过SwapEndian()的转换才可得到正确的值。

但是如果我们将一个文件的内容通过socket从Linux传到AIX上,则不需要关注big与small的转换问题,这是因为本地的文件系统写与读都采用同样的字节序,所以程序本身的代码无需再做额外的工作。文件即内存,除非程序需要自己解读文件中的内容。

09-26 18:52