|
by 动物园墙垮
我今天测试发现ACE_InputCDR和ACE_OutputCDR并不是那么简单。
如果稍微不注意就会出现一些奇怪的字节错位的情况。
在这里我总结一下使用的规则:
- ACE_OutputCDR out(mb);
- out << ?? ; //这种方法简称out
- 例一:
- 如果out 了一个short再out一个long
- out << (ACE_CDR::UShort)1;
- out << (ACE_CDR:ong)2;
- ACE_LOG_MSG->log_hexdump( LM_DEBUG , mb->base() , out.length() , "t");
- 字节将成为如下排列(16进制) xx xx ?? ?? xx xx xx xx
- 其中,问号部分即是因为在long写入时进行的按long长度对齐。该数据是无意义的
-
- 例二:
- 如果out了一个char再out一个 short
- 字节将成为如下排列 xx ?? xx xx
- 其中,问号部分即是因为在short写入时进行的按short长度对齐。该数据是无意义的
-
-
- 例三:
- 如果out了一个short再out一个char
- 字节将成为如下排列 xx xx xx
- 这里输入的char不会造成对齐问题,因为char只有一个字节(都是倍数)
-
- 例四:
- 如果out了一个short再out一个char 再out 一个 long
- 字节将成为如下排列 xx xx xx ?? xx xx xx xx
-
复制代码
按照以上可总结出,每out一个类型的数据时,输出流将自动按照这个输入类型的长度序对齐,如果没有对齐,则自动填充。
导致读数据时产生非常多的问题。(你不见CNPV1中都是强转成ACE_CDR::ULong吗?这下知道了吧)。
解决方案有两种:
方案一:全部一种类型吧!比如全部用ACE_CDR::ULong
不过这种方法通常不适合实际的应用。让偶动物园墙垮来帮大家解决这个心结。:) 西西,请看下一方案。
方案二:
大家都会觉得这玩意被做出来怎么就不好用呢?没道理吧。我也觉得没道理,所以为了证实ACE开发者都是大牛,偶就把ACE的代码挖出来给大家看看,
看看这里到底有着什么样的玄机?
我们就拿ACE_ULong来开刀:
大家翻开CDR_Stream.inl文件,找到以下语句
- ACE_INLINE ACE_CDR::Boolean
- operator<< (ACE_OutputCDR &os, ACE_CDR::ULong x)
- {
- os.write_ulong (x);
- return (ACE_CDR::Boolean) os.good_bit ();
- }
- 继续下去 os.write_ulong (x);
- ACE_INLINE ACE_CDR::Boolean
- ACE_OutputCDR::write_ulong (ACE_CDR::ULong x)
- {
- const void *temp = &x;
- return this->write_4 (reinterpret_cast<const ACE_CDR::ULong*> (temp));
- }
- 继续跟踪this->write_4 (reinterpret_cast<const ACE_CDR::ULong*> (temp));
- ACE_CDR::Boolean
- ACE_OutputCDR::write_4 (const ACE_CDR::ULong *x)
- {
- char *buf = 0;
- if (this->adjust (ACE_CDR:ONG_SIZE, buf) == 0)
- {
- ....
- }
- }
- 再继续adjust (ACE_CDR:ONG_SIZE, buf)
- ACE_INLINE int
- ACE_OutputCDR::adjust (size_t size, char*& buf)
- {
- return this->adjust (size, size, buf);
- }
- 继续 this->adjust (size, size, buf);
- ACE_INLINE int
- ACE_OutputCDR::adjust (size_t size,
- size_t align,
- char*& buf)
- {
- if (!this->current_is_writable_)
- return this->grow_and_adjust (size, align, buf);
- #if !defined (ACE_LACKS_CDR_ALIGNMENT)
- const size_t offset =
- ACE_align_binary (this->current_alignment_, align)
- - this->current_alignment_;
- buf = this->current_->wr_ptr () + offset;
- #else
- buf = this->current_->wr_ptr ();
- #endif /* ACE_LACKS_CDR_ALIGNMENT */
- char *end = buf + size;
- if (end <= this->current_->end () &&
- end >= buf)
- {
- #if !defined (ACE_LACKS_CDR_ALIGNMENT)
- this->current_alignment_ += offset + size;
- #endif /* ACE_LACKS_CDR_ALIGNMENT */
- this->current_->wr_ptr (end);
- return 0;
- }
- return this->grow_and_adjust (size, align, buf);
- }
- 好!我们找到了,原来校正的代码就在这里!仔细看看
- #if !defined (ACE_LACKS_CDR_ALIGNMENT)
- 这里说明,如果你定义了ACE_LACKS_CDR_ALIGNMENT,那么ACE就不会帮你校准对齐字节啦!
- 哈哈,是不是很兴奋?别着急,让我们动手
- 打开config.h文件,加入以下一句
- #define ACE_LACKS_CDR_ALIGNMENT
- 重新编译ACE,好,将新的lib加入工程
- (如果你用了aced.dll或ace.dll,注意路径,或把新的dll拷贝到system32目录下)
- 让我们来运行一下原来的程序
- out << (ACE_CDR::UShort)1;
- out << (ACE_CDR:ong)2;
- ACE_LOG_MSG->log_hexdump( LM_DEBUG , mb->base() , out.length() , "t");
- 字节将成为如下排列(16进制) xx xx xx xx xx xx
- 哈哈!你再试试以上四个例子,会发现都没有问题了!
- 那么,从现在开始,你还需要写自己的整编和解编的包装类吗?我看没有必要了吧。还不快动手修改你的工程?
- 补充:
- 如果不这么做。那么在接收端用ACE_IntputCDR进行 >> 操作时。如果没有进行读时的强制转换
- 比如 没有这样写
- ACE_CDR::Char c;
- ACE_CDR::UShort s;
- ACE_InputCDR in(...);
- in >> (ACE_CDR::ULong)c;
- in >> (ACE_CDR::ULong)s;
- 而是这样写:
- ACE_InputCDR in(...);
- in >> c;
- in >> s;
- 必出各种字节乱码问题。因为中间多了CORBA的marshaling 与demarshaling对齐数据。
- 如果按照以上方法重新编译ACE后。即可省事多了(同时也节省了网络流量)
- ACE_OutputCDR out(..);
- out << c;
- out << s;
- ------------------------------------
- ACE_InputCDR in(...);
- in >> c;
- in >> s;
复制代码
无须任何类型转换。绝不出错。
再次声明。你不必自己写整编和解编。该论坛多次讨论过该问题。这是一个非常好的解决之道。
[ 本帖最后由 peakzhang 于 2007-12-26 22:28 编辑 ] |
|