使用ACE_CDR类进行网络编解码(5-3)
2009-09-25 07:21
148 查看
这次我们来处理边界调整的问题。留意下面的代码片段:
view plain
copy to clipboard
print
?
char
buf[6] = {0};
ACE_OutputCDR ocdr(buf, 6, ACE_CDR::BYTE_ORDER_BIG_ENDIAN);
ACE_CDR::ULong temp1 = 88;
ACE_CDR::UShort temp2 = 66;
ocdr << temp1;
ocdr << temp2;
int
result = peer.sendn(buf, 6);
上面的代码将两个数据压到buf中。这里面有一个隐藏的BUG。第二行用一个buf来构造ACE_OutputCDR对象
时,ACE_OutputCDRr构造函数会进行一个复杂的操作。它先用这个buf构造一个ACE_Message_Block,然后对这个
ACE_Message_Block调用ACE_CDR::mb_align方法,进行一次边界调整。
如果刚好buf的起点不在4字节的边界上(不能整除4),则会将ACE_Message_Block的起点后移到4字节对齐的边界上。这会造成两个
可能的后果。如果调整的确发生了(假如往后调整了2个字节),那么上述代码最后一行发送的内容,实际上就是错误的,因为错开了2个字节。更为严重的错误是
我们的buf刚好是6个字节,我们也写入了6个字节,但是如果ACE_OutputCDR替我们做了一次调整的话,在写入的时候就会越界,破坏堆栈(覆写
buf数组后面的两个字节)。
解决的方式有两个。如果是像上述的代码一样,用CDR类来对原始的buffer进行处理,那么可以通过在config.h文件中定义下例的宏来屏蔽对齐行为。
view plain
copy to clipboard
print
?
#define ACE_CDR_IGNORE_ALIGNMENT
注意要重新编译ACE。
另外一种方法是,如果是ACE在项目中用得比较普及的话,建议不要直接用原始buffer,改用ACE_Message_Block。实际上对齐时
是调整了内部的ACE_Message_Block的base指针。如果总是通过ACE_Message_Block的base方法来得到实际
buffer的起始,就不用担心会发生错位。这里唯一要注意的就是要为可能的调整留出空间,避免上面说的溢出。比如下面的代码:
ACE_Message_Block mb(1024 + ACE_CDR::MAX_ALIGNMENT);
我们需要一个1024大小的buffer,但是在实际申请空间时加一个冗余值 ,对齐最大也不可能超过这个冗余,这样就避免了压入数据时引起越界。
ACE进行一次对齐的原因是为了加快内存操作。结合前面“紧缩”部分的描述,我们可以知道,在缺省情况下,ACE在编解码时不但将Buffer的起
始外进行对齐处理,里面的数据类型不论大小也是按4字节对齐的。有兴趣的可以看一下MAX_ALIGNMENT这个冗余量的值是8而不是4,我猜可能是为
了兼容64位机器
view plain
copy to clipboard
?
char
buf[6] = {0};
ACE_OutputCDR ocdr(buf, 6, ACE_CDR::BYTE_ORDER_BIG_ENDIAN);
ACE_CDR::ULong temp1 = 88;
ACE_CDR::UShort temp2 = 66;
ocdr << temp1;
ocdr << temp2;
int
result = peer.sendn(buf, 6);
char buf[6] = {0}; ACE_OutputCDR ocdr(buf, 6, ACE_CDR::BYTE_ORDER_BIG_ENDIAN); ACE_CDR::ULong temp1 = 88; ACE_CDR::UShort temp2 = 66; ocdr << temp1; ocdr << temp2; int result = peer.sendn(buf, 6);
上面的代码将两个数据压到buf中。这里面有一个隐藏的BUG。第二行用一个buf来构造ACE_OutputCDR对象
时,ACE_OutputCDRr构造函数会进行一个复杂的操作。它先用这个buf构造一个ACE_Message_Block,然后对这个
ACE_Message_Block调用ACE_CDR::mb_align方法,进行一次边界调整。
如果刚好buf的起点不在4字节的边界上(不能整除4),则会将ACE_Message_Block的起点后移到4字节对齐的边界上。这会造成两个
可能的后果。如果调整的确发生了(假如往后调整了2个字节),那么上述代码最后一行发送的内容,实际上就是错误的,因为错开了2个字节。更为严重的错误是
我们的buf刚好是6个字节,我们也写入了6个字节,但是如果ACE_OutputCDR替我们做了一次调整的话,在写入的时候就会越界,破坏堆栈(覆写
buf数组后面的两个字节)。
解决的方式有两个。如果是像上述的代码一样,用CDR类来对原始的buffer进行处理,那么可以通过在config.h文件中定义下例的宏来屏蔽对齐行为。
view plain
copy to clipboard
?
#define ACE_CDR_IGNORE_ALIGNMENT
#define ACE_CDR_IGNORE_ALIGNMENT
注意要重新编译ACE。
另外一种方法是,如果是ACE在项目中用得比较普及的话,建议不要直接用原始buffer,改用ACE_Message_Block。实际上对齐时
是调整了内部的ACE_Message_Block的base指针。如果总是通过ACE_Message_Block的base方法来得到实际
buffer的起始,就不用担心会发生错位。这里唯一要注意的就是要为可能的调整留出空间,避免上面说的溢出。比如下面的代码:
ACE_Message_Block mb(1024 + ACE_CDR::MAX_ALIGNMENT);
ACE_Message_Block mb(1024 + ACE_CDR::MAX_ALIGNMENT);
我们需要一个1024大小的buffer,但是在实际申请空间时加一个冗余值 ,对齐最大也不可能超过这个冗余,这样就避免了压入数据时引起越界。
ACE进行一次对齐的原因是为了加快内存操作。结合前面“紧缩”部分的描述,我们可以知道,在缺省情况下,ACE在编解码时不但将Buffer的起
始外进行对齐处理,里面的数据类型不论大小也是按4字节对齐的。有兴趣的可以看一下MAX_ALIGNMENT这个冗余量的值是8而不是4,我猜可能是为
了兼容64位机器
相关文章推荐
- 使用ACE进行网络编程
- 使用ACE进行网络编程
- 使用ACE进行网络编程
- 使用ACE进行网络连接失败
- 使用 ffmpeg 进行网络推流:拉流->解封装->解码->处理原始数据(音频、视频)->编码->编码->推流
- 使用ACE进行网络编程
- 直接使用socket_TCP进行网络游戏开发
- Android 通过WebService进行网络编程,使用工具类轻松实现
- 在silverlight中进行网络交互(下) 使用代理与web服务交互
- 封装项目整体架构,访问网络数据,展示列表数据,根据图片数量的不同来多条目加载,使用Universal-Image-Loader进行图片加载
- Android 通过WebService进行网络编程,使用工具类轻松实现
- ios开发---对网络请求的数据进行解码(Unicode)
- 使用epoll进行高性能网络编程(收藏)
- 已禁用对分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具启用 DTC 以便在 MSDTC 安全配置中进行网络访问。 与基础事务管理器的通信失败。 .net 代码里 写事务代码
- 使用netmeeting进行网络培训
- [ZZ]使用命名管道通过网络在进程之间进行通信
- 使用tcpdump进行网络包分析
- Android之使用HttpURLConnection进行网络访问
- 如何使用wmwifirouter 进行网络共享,使usb to wifi成为AP无线接入呢。
- 在Java中使用NIO进行网络编程