ACE_Message_Block消息数据类
ACE_Message_Block
ACE_Message_Block用于构建“固定”和“可变”长度的消息。ACE_Message_Block可以将多条消息连接在一起,形成一个链表,从而支持复合消息。ACE_Message_Block内部结构图如下:
头文件“Message_Block.h”。
1:ACE_Message_Block初始化与释放
初始化一般用以下操作实现:
ACE_NEW_NORETURN (m_pRcvmb,ACE_Message_Block ()); ACE_Message_Block* p = new ACE_Message_Block();
这两种方式都可以实现ACE_Message_Block的new操作。ACE定义了一组申请内存的宏,内部都实现了new操作符。这组宏定义在如下:
# if defined (ACE_HAS_NEW_NOTHROW)
# define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
do { POINTER = new (ACE_nothrow) CONSTRUCTOR; \
if (POINTER == ) { errno = ENOMEM; return RET_VAL; } \
} while ()
# define ACE_NEW(POINTER,CONSTRUCTOR) \
do { POINTER = new(ACE_nothrow) CONSTRUCTOR; \
if (POINTER == ) { errno = ENOMEM; return; } \
} while ()
# define ACE_NEW_NORETURN(POINTER,CONSTRUCTOR) \
do { POINTER = new(ACE_nothrow) CONSTRUCTOR; \
if (POINTER == ) { errno = ENOMEM; } \
} while () # else # define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
do { try { POINTER = new CONSTRUCTOR; } \
catch (ACE_bad_alloc) { ACE_del_bad_alloc errno = ENOMEM; POINTER = ; return RET_VAL; } \
} while () # define ACE_NEW(POINTER,CONSTRUCTOR) \
do { try { POINTER = new CONSTRUCTOR; } \
catch (ACE_bad_alloc) { ACE_del_bad_alloc errno = ENOMEM; POINTER = ; return; } \
} while () # define ACE_NEW_NORETURN(POINTER,CONSTRUCTOR) \
do { try { POINTER = new CONSTRUCTOR; } \
catch (ACE_bad_alloc) { ACE_del_bad_alloc errno = ENOMEM; POINTER = ; } \
} while ()
# endif /* ACE_HAS_NEW_NOTHROW */
值得注意的是,ACE_Message_Block有多个构造函数,最常用的一个构造函数定义为:
ACE_Message_Block (size_t size,
ACE_Message_Type type = MB_DATA,
ACE_Message_Block *cont = ,
const char *data = ,
ACE_Allocator *allocator_strategy = ,
ACE_Lock *locking_strategy = ,
unsigned long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY,
const ACE_Time_Value &execution_time = ACE_Time_Value::zero,
const ACE_Time_Value &deadline_time = ACE_Time_Value::max_time,
ACE_Allocator *data_block_allocator = ,
ACE_Allocator *message_block_allocator = );
在该构造函数内部,ACE_Message_Block调用了init_i函数,init_i内部调用了ACE_Data_Block的构造函数。ACE_Data_Block定义了一个char* base_ 指针,其构造函数会调用C风格的malloc方法为base_申请大小为size的空间。也就是说,ACE_Message_Block真正的数据载体是ACE_Data_Block。其实现代码为:
//ACE_Message_Block内部申请ACE_Data_Block的空间
ACE_NEW_MALLOC_RETURN (db,static_cast<ACE_Data_Block *> (data_block_allocator->malloc (sizeof (ACE_Data_Block))),
ACE_Data_Block (size,
msg_type,
msg_data,
allocator_strategy,
locking_strategy,
flags,
data_block_allocator),-); //ACE_Data_Block内部为base_申请大小为size的空间
if (msg_data == )
{
ACE_ALLOCATOR (this->base_,(char *) this->allocator_strategy_->malloc (size));
#if defined (ACE_INITIALIZE_MEMORY_BEFORE_USE)
(void) ACE_OS::memset (this->base_,'\0',size);
#endif /* ACE_INITIALIZE_MEMORY_BEFORE_USE */
}
释放ACE_Message_Block,调用release方法即可。release方法会将消息的引用计数减1,如果消息的引用计数为0,则释放该消息。
2:ACE_Message_Block写入数据
ACE_Message_Block内部有读地址和写地址,ACE_Message_Block的长度是写地址减去读地址的值。其定义为:
//读写地址
/// Pointer to beginning of next read.
size_t rd_ptr_;
/// Pointer to beginning of next write.
size_t wr_ptr_; //长度
ACE_Message_Block::length (void) const
{
ACE_TRACE ("ACE_Message_Block::length");
return this->wr_ptr_ - this->rd_ptr_;
}
rd_ptr()和wr_ptr()分别用于设置和获取读写地址的值。
将buffer中的数据复制到ACE_Message_Block中,需要调用copy函数。copy函数内部用memcpy实现,将buf的size个BYTE拷贝到以wr_ptr_地址为首的地址上,并将wr_ptr_的值加上size,其实现为:
int ACE_Message_Block::copy (const char *buf, size_t n)
{
ACE_TRACE ("ACE_Message_Block::copy");
/*size_t len = static_cast<size_t> (this->end () - this->wr_ptr ());*/
// Note that for this to work correct, end () *must* be >= mark ().
size_t len = this->space ();
if (len < n)
{
errno = ENOSPC;
return -;
}
else
{
(void) ACE_OS::memcpy (this->wr_ptr (),buf,n);
this->wr_ptr (n);
return ;
}
}
3:ACE_Message_Block复制操作
ACE_Message_Block提供了clone和duplicate两个操作,clone是深复制,duplicate是浅复制,仅为消息的引用计数加1。
4:ACE_Message_Block消息链
ACE_Message_Block内部定义3个指针:
/// Pointer to next message block in the chain.
ACE_Message_Block *cont_;
/// Pointer to next message in the list.
ACE_Message_Block *next_;
/// Pointer to previous message in the list.
ACE_Message_Block *prev_;
分别用重载函数cont()、next()、prev()来设置和获取邻居消息。其中,cont用于将复合消息连接在一起,next和prev用于连接消息链上的简单消息。
一个消息链的示例如下:
#include "ace/OS.h"
#include "ace/Message_Block.h" int main (int argc, char *argv[])
{
ACE_Message_Block *head = new ACE_Message_Block (BUFSIZ);
ACE_Message_Block *mblk = head; for (;;) {
ssize_t nbytes = ACE::read_n (ACE_STDIN,mblk->wr_ptr (),mblk->size () ) ;
if (nbytes <= )
break; // Break out at EOF or error.
// Advance the write pointer to the end of the buffer.
mblk->wr_ptr (nbytes);
// Allocate message block and chain it at the end of list.
mblk->cont (new ACE_Message_Block (BUFSIZ));
mblk = mblk->cont ();
}
// Print the contents of the list to the standard output.
for (mblk = head; mblk != ; mblk = mblk->cont ())
ACE::write_n (ACE_STDOUT, mblk->rd_ptr (), mblk->length ());
head->release (); // This releases all the memory in the chain.
return ;
}
5:size()、length()、space()、capacity()
一张图说明ACE_Message_Block这几个函数的含义:

length= wr_ptr - rd_ptr;
space = mark - wr_ptr;
size = mark - base;
capacity = end - base;
其中,capacity和size的关系参考stl的capacity和size。int size (size_t length)可以动态申请空间。
C++ Network Programming. Volume 1: Mastering Complexity with ACE and Patterns
ACE_Message_Block消息数据类的更多相关文章
- phpMemcache消息队列类
<?php /** * Memcache 消息队列类 */ class QMC { const PREFIX = 'ASDFASDFFWQKE'; /** * 初始化 mc * @staticv ...
- 【转】解决Maxwell发送Kafka消息数据倾斜问题
最近用Maxwell解析MySQL的Binlog,发送到Kafka进行处理,测试的时候发现一个问题,就是Kafka的Offset严重倾斜,三个partition,其中一个的offset已经快200万了 ...
- 代码的坏味道(16)——纯稚的数据类(Data Class)
坏味道--纯稚的数据类(Data Class) 特征 纯稚的数据类(Data Class) 指的是只包含字段和访问它们的getter和setter函数的类.这些仅仅是供其他类使用的数据容器.这些类不包 ...
- Java数据类型和MySql数据类型对应一览
类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) 描述 VARCHAR L+N VARCHAR java.lang.String 12 CHAR N ...
- 数据类型和typeof操作符
虽然学习js有一段时间了,但是对js的基础语法却是有些生疏.最近在看jquery源码,决定随带总结一些基础的语法知识.今天总结一下数据类型和typeof,这在写js的时候,是不得不知道的知识. 数据类 ...
- Kafka consumer处理大消息数据问题
案例分析 处理kafka consumer的程序的时候,发现如下错误: ERROR [2016-07-22 07:16:02,466] com.flow.kafka.consumer.main.Kaf ...
- 如何创建一个要素数据类 IField,IFieldEdit,IFields,IFieldsEditI,GeometryDef,IGeometryDefEdit接口
如何创建一个要素数据类 创建要素类用到了IFeatureWorkspace.CreateFeatureClass方法,在这个方法中有众多的参数,为了满足这些参数,我们要学习和了解下面的接口. IFie ...
- Kotlin——最详细的数据类、密封类详解
在前面几个章节章节中,详细的讲解了Koltin中的接口类(Interface).枚举类(Enmu),还不甚了解的可以查看我的上一篇文章Kotlin--接口类.枚举类详解.当然,在Koltin中,除了接 ...
- 四种途径提高RabbitMQ传输消息数据的可靠性(一)
前言 RabbitMQ虽然有对队列及消息等的一些持久化设置,但其实光光只是这一个是不能够保障数据的可靠性的,下面我们提出这样的质疑: (1)RabbitMQ生产者是不知道自己发布的消息是否已经正确达到 ...
随机推荐
- ElasticSearch(8)-分布式搜索
分布式搜索的执行方式 在继续之前,我们将绕道讲一下搜索是如何在分布式环境中执行的. 它比我们之前讲的基础的增删改查(create-read-update-delete ,CRUD)请求要复杂一些. 注 ...
- out和ref之间的区别
首先:两者都是按引用传递的,使用后都将改变原来参数的数值. 其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所 ...
- 关于Java集合
之前关于java集合认识,虽然理解,但是总是忘记关键点,今明两天写一篇关于集合的随笔
- matlab里plot画多幅图像、设置总标题、legend无边框
%%绘图 suptitle('公路') %总标题subplot(2,2,1);plot(x,y11,'r-') hold onplot(x,y21,'b-')xlabel('方向')ylabel(' ...
- 【linux-shell】rsync
https://en.wikipedia.org/wiki/Rsync https://en.wikipedia.org/wiki/Andrew_Tridgell 安德鲁.锤子,发布了rsync的第一 ...
- python--day4--迭代器、生成器
列表生成式: 需求:列表[1,2,3,4,5,6,7,8,9]每个值加1,实现的方法: a = [0,1,2,3,4,5,6,7,8,9] b = [] for i in a:b.append(i+1 ...
- JMM内存管理
原文地址http://www.cnblogs.com/BangQ/p/4045954.html 原本准备把内存模型单独放到某一篇文章的某个章节里面讲解,后来查阅了国外很多文档才发现其实JVM内存模型的 ...
- java中部分知识点的验证实现
java中运算符重载 满足以下条件的两个或多个方法构成"重载"关系: (1)方法名相同: (2)参数类型不同,参数个数不同,或者是参数类型的顺序不同. 注意:方法的返回值不作为方法 ...
- PHP来实现文件上传
文件php <?phpif ($_FILES["file"]["error"] > 0){ echo '错误: ' . $_FILES[" ...
- UML类图几种关系总结
在UML类图中,常见的有以下几种关系: 泛化(Generalization), 实现(Realization),关联(Association),聚合(Aggregation),组合(Composit ...

