关于网络编程中字节序转换优化的思考

       总所周知,不同系统平台间的内存访问字节序不同,有所谓big-endien和little-end两种。因此,为实现通用的通信程序,通常的做法是统一采用big-endian字节序作为网络标准字节序,到主机端根据情况进行转换,即使用ntoh*和hton*这两类宏或函数。

 

       然而,就效率方面来讲,对于同构的系统平台,这样做未免有些浪费。尤其是我们常见的x86平台,每次通信,发送端都要先把数据从little-endien转成big-endien,接收端再执行相反的过程转回来,相当于做了两次无用功。有时,即使对于异构平台,这些转换过程如果实现为函数调用也是浪费的。

 

       因此,考虑对同构平台作一些优化,我们可以采取非传统的思路。ACE的CDR_Stream就采用了这种设计思路进行优化,宏常量ACE_ENABLE_SWAP_ON_WRITE在编译时确定是否进行字节序转换,缺省是关闭的,即不进行转换。例如下面的代码:

ACE_CDR::Boolean ACE_OutputCDR::write_2 (const ACE_CDR::UShort *x) { char *buf = 0; if (this->adjust (ACE_CDR::SHORT_SIZE, buf) == 0) { #if !defined (ACE_ENABLE_SWAP_ON_WRITE) *reinterpret_cast (buf) = *x; return true; #else if (!this->do_byte_swap_) { *reinterpret_cast (buf) = *x; return true; } else { ACE_CDR::swap_2 (reinterpret_cast (x), buf); return true; } #endif /* ACE_ENABLE_SWAP_ON_WRITE */ } return false; }

 

      当然,在保证能在异构平台件正常通信的前提下,字节序转换是必要的。不过即使这种情况,也有两种选择。一种当然是传统的方式,即将通信数据统一转为网络字节序;另一种是在发送数据时不进行字节序转换,而由发送方标明本身的字节序,仍然保持主机字节序在网络中传输,由接受端确定是否进行转换。这就涉及到一个字节序标识存放的问题。ACE经典教程《C++NPv1》给出的例子,是将字节序标识放在每个通信包头的第一个字节。这样做当然可以解决问题,不过也带来了额外的开销,就是每个包头中多了一个字节。

      采用标识字节序的方式优化,另一种效率更高的做法,就是在通信连接建立之初,标识和确定通信双方的字节序。我们可以在应用协议中约定:建立连接后发送的第一个数据包中,包含了网络字节序信息,以后的数据包都不包含这一信息。之所以能这么优化,是因为已知的系统平台都不会在运行时改变本机字节序,而且可预知的未来也会继续保持这一特性。

 

     优化往往会带来一些限制和复杂性,上述字节序转换的优化也如此,这要求各通信端都采用新的字节序标识协议。对于这一点,我们别忘了要考虑不同语言的实现。

 

 

 

你可能感兴趣的:(C/C++编程,分布式系统,优化,网络,编程,平台,stream,byte)