找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 7006|回复: 5

关于ACE_InputCDR和ACE_OutputCDR读写数据时的经验[原创*必读!]

[复制链接]
发表于 2007-12-26 22:27:51 | 显示全部楼层 |阅读模式
by 动物园墙垮
我今天测试发现ACE_InputCDRACE_OutputCDR并不是那么简单。
如果稍微不注意就会出现一些奇怪的字节错位的情况。

在这里我总结一下使用的规则:
  1.          ACE_OutputCDR out(mb);
  2.          out  << ?? ;     //这种方法简称out
  3.          例一:
  4.          如果out 了一个short再out一个long
  5.          out << (ACE_CDR::UShort)1;
  6.          out << (ACE_CDR:ong)2;
  7.          ACE_LOG_MSG->log_hexdump( LM_DEBUG , mb->base() , out.length() , "t");
  8.          字节将成为如下排列(16进制)            xx xx ?? ?? xx xx xx xx
  9.          其中,问号部分即是因为在long写入时进行的按long长度对齐。该数据是无意义的
  10.          
  11.          例二:
  12.          如果out了一个char再out一个 short
  13.          字节将成为如下排列            xx  ??  xx xx
  14.          其中,问号部分即是因为在short写入时进行的按short长度对齐。该数据是无意义的
  15.          
  16.          
  17.          例三:
  18.          如果out了一个short再out一个char
  19.          字节将成为如下排列            xx  xx    xx
  20.          这里输入的char不会造成对齐问题,因为char只有一个字节(都是倍数)
  21.          
  22.          例四:
  23.          如果out了一个short再out一个char 再out 一个 long
  24.          字节将成为如下排列            xx  xx  xx  ??  xx  xx  xx  xx
  25.          
复制代码

         按照以上可总结出,每out一个类型的数据时,输出流将自动按照这个输入类型的长度序对齐,如果没有对齐,则自动填充。
     导致读数据时产生非常多的问题。(你不见CNPV1中都是强转成ACE_CDR::ULong吗?这下知道了吧)。

解决方案有两种:
方案一:全部一种类型吧!比如全部用ACE_CDR::ULong

    不过这种方法通常不适合实际的应用。让偶动物园墙垮来帮大家解决这个心结。:) 西西,请看下一方案。


方案二:

大家都会觉得这玩意被做出来怎么就不好用呢?没道理吧。我也觉得没道理,所以为了证实ACE开发者都是大牛,偶就把ACE的代码挖出来给大家看看,
看看这里到底有着什么样的玄机?

我们就拿ACE_ULong来开刀:

大家翻开CDR_Stream.inl文件,找到以下语句
  1. ACE_INLINE ACE_CDR::Boolean
  2. operator<< (ACE_OutputCDR &os, ACE_CDR::ULong x)
  3. {
  4.   os.write_ulong (x);
  5.   return (ACE_CDR::Boolean) os.good_bit ();
  6. }
  7. 继续下去 os.write_ulong (x);
  8. ACE_INLINE ACE_CDR::Boolean
  9. ACE_OutputCDR::write_ulong (ACE_CDR::ULong x)
  10. {
  11.   const void *temp = &x;
  12.   return this->write_4 (reinterpret_cast<const ACE_CDR::ULong*> (temp));
  13. }
  14. 继续跟踪this->write_4 (reinterpret_cast<const ACE_CDR::ULong*> (temp));
  15. ACE_CDR::Boolean
  16. ACE_OutputCDR::write_4 (const ACE_CDR::ULong *x)
  17. {
  18.   char *buf = 0;
  19.   if (this->adjust (ACE_CDR:ONG_SIZE, buf) == 0)
  20.     {
  21.        ....
  22.     }
  23. }
  24. 再继续adjust (ACE_CDR:ONG_SIZE, buf)
  25. ACE_INLINE int
  26. ACE_OutputCDR::adjust (size_t size, char*& buf)
  27. {
  28.   return this->adjust (size, size, buf);
  29. }
  30. 继续 this->adjust (size, size, buf);
  31. ACE_INLINE int
  32. ACE_OutputCDR::adjust (size_t size,
  33.                        size_t align,
  34.                        char*& buf)
  35. {
  36.   if (!this->current_is_writable_)
  37.     return this->grow_and_adjust (size, align, buf);
  38. #if !defined (ACE_LACKS_CDR_ALIGNMENT)
  39.   const size_t offset =
  40.     ACE_align_binary (this->current_alignment_, align)
  41.     - this->current_alignment_;
  42.   buf = this->current_->wr_ptr () + offset;
  43. #else
  44.   buf = this->current_->wr_ptr ();
  45. #endif /* ACE_LACKS_CDR_ALIGNMENT */
  46.   char *end = buf + size;
  47.   if (end <= this->current_->end () &&
  48.       end >= buf)
  49.     {
  50. #if !defined (ACE_LACKS_CDR_ALIGNMENT)
  51.       this->current_alignment_ += offset + size;
  52. #endif /* ACE_LACKS_CDR_ALIGNMENT */
  53.       this->current_->wr_ptr (end);
  54.       return 0;
  55.     }
  56.   return this->grow_and_adjust (size, align, buf);
  57. }
  58. 好!我们找到了,原来校正的代码就在这里!仔细看看
  59. #if !defined (ACE_LACKS_CDR_ALIGNMENT)
  60. 这里说明,如果你定义了ACE_LACKS_CDR_ALIGNMENT,那么ACE就不会帮你校准对齐字节啦!
  61. 哈哈,是不是很兴奋?别着急,让我们动手
  62. 打开config.h文件,加入以下一句
  63. #define ACE_LACKS_CDR_ALIGNMENT
  64. 重新编译ACE,好,将新的lib加入工程
  65. (如果你用了aced.dll或ace.dll,注意路径,或把新的dll拷贝到system32目录下)
  66. 让我们来运行一下原来的程序
  67.          out << (ACE_CDR::UShort)1;
  68.          out << (ACE_CDR:ong)2;
  69.          ACE_LOG_MSG->log_hexdump( LM_DEBUG , mb->base() , out.length() , "t");
  70.          字节将成为如下排列(16进制)            xx xx      xx xx xx xx
  71. 哈哈!你再试试以上四个例子,会发现都没有问题了!
  72. 那么,从现在开始,你还需要写自己的整编和解编的包装类吗?我看没有必要了吧。还不快动手修改你的工程?
  73. 补充:
  74. 如果不这么做。那么在接收端用ACE_IntputCDR进行 >> 操作时。如果没有进行读时的强制转换
  75. 比如 没有这样写
  76. ACE_CDR::Char c;
  77. ACE_CDR::UShort s;
  78. ACE_InputCDR in(...);
  79. in >> (ACE_CDR::ULong)c;
  80. in >> (ACE_CDR::ULong)s;
  81. 而是这样写:
  82. ACE_InputCDR in(...);
  83. in >>  c;
  84. in >> s;
  85. 必出各种字节乱码问题。因为中间多了CORBA的marshaling 与demarshaling对齐数据。
  86. 如果按照以上方法重新编译ACE后。即可省事多了(同时也节省了网络流量)
  87. ACE_OutputCDR out(..);
  88. out << c;
  89. out << s;
  90. ------------------------------------
  91. ACE_InputCDR in(...);
  92. in >>  c;
  93. in >> s;
复制代码

无须任何类型转换。绝不出错。
再次声明。你不必自己写整编和解编。该论坛多次讨论过该问题。这是一个非常好的解决之道。



[ 本帖最后由 peakzhang 于 2007-12-26 22:28 编辑 ]
 楼主| 发表于 2007-12-26 22:30:46 | 显示全部楼层
疑问1:

(你不见CNPV1中都是强转成ACE_CDR::ULong吗?这下知道了吧)

这个我没有找到,是否所有的都这样转了?

疑问2:

比如 没有这样写

ACE_CDR::Char c;

ACE_CDR::UShort s;

ACE_InputCDR in(...);

in >> (ACE_CDR::ULong)c;

in >> (ACE_CDR::ULong)s;

这样的写法是否有点太强求了,如果你是按照Char和UShort整编的,那只需要使用

in >>  c;

in >> s;

这样的写法就能真确解编。

疑问3:

ACE_LACKS_CDR_ALIGNMENT是用来进行决定是否要对齐操作的,你把他屏蔽了,是否会造成其他后果,比方说网络字节对齐等。
 楼主| 发表于 2007-12-26 22:30:54 | 显示全部楼层
加上ACE_LACKS_CDR_ALIGNMENT宏,应该会影响CORBA,因为默认要8字节对齐。但我们如果不用CORBA,用此宏无妨。
我自己试验过,如果没有此宏,解码的确会出现对齐的错误。
 楼主| 发表于 2007-12-26 22:31:02 | 显示全部楼层
我的实际测试代码:
  1. ACE_Message_Block out_mb(1024);
  2. ACE_OutputCDR out(&out_mb);
  3. out<<(ACE_CDR::UShort)<<1;
  4. out<<(ACE_CDR:ong)<<2;
  5. out<<(ACE_CDR::Char)<<3;
  6. out<<(ACE_CDR::UShort)<<4;
  7. out<<(ACE_CDR::UShort)<<5;
  8. out<<(ACE_CDR::Char)<<6;
  9. out<<(ACE_CDR::UShort)<<7;
  10. out<<(ACE_CDR::Char)<<8;
  11. out<<(ACE_CDR:ong)<<9;
  12. ACE_LOG_MSG->log_hexdump(LM_DEBUG, out_mb.base(), out.length(), "t");
  13. ACE_InputCDR in(out);
  14. ACE_CDR::UShort a;
  15. ACE_CDR:ong b;
  16. ACE_CDR::Char c;
  17. ACE_CDR::UShort d;
  18. ACE_CDR::UShort e;
  19. ACE_CDR::Char f;
  20. ACE_CDR::UShort g;
  21. ACE_CDR::Char h;
  22. ACE_CDR:ong i;
  23. in >> a;
  24. in >> b;
  25. in >> c;
  26. in >> d;
  27. in >> e;
  28. in >> f;
  29. in >> g;
  30. in >> h;
  31. in >> i;
复制代码
测试结果:

1.能正确解编

2.

t-HEXDUMP 24 bytes

01 00 cd cd 02 00 00 00 03 cd 04 00 05 00 06 cd

07 00 08 cd 09 00 00 00
 楼主| 发表于 2007-12-26 22:31:35 | 显示全部楼层
我就是说的不用CORBA的情况。ACE_LACKS_CDR_ALIGNMENT这个宏也就是为不用CORBA字节对齐时使用的
 楼主| 发表于 2007-12-26 22:31:44 | 显示全部楼层
回sim。

并不是所有应用都需要对齐字节,不对齐字节并不表示容易出现解码错误。用了该宏,那么在收发两边按照同样的顺序读出,也不需要增加强制类型转换也不会出错。

根据不同的应用选择不同方法
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-12-4 16:14 , Processed in 0.016741 second(s), 5 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表