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生产者是不知道自己发布的消息是否已经正确达到 ...
随机推荐
- Java多线程的信号量
Java的信号量主要的作用是控制线程对资源的访问例如我一个线程池里面有100个线程等待执行,但是我允许最多同时运行5个线程,这5个线程只有其中一个线程执行完毕后,在线程池中等待的线程才能进入开始执行, ...
- Form提交时隐藏Token验证
前端声称一个Token @Html.AntiForgeryToken() 后台对Token进行验证 AntiForgery.Validate();
- 【ubuntu】开机启动
背景 在ubuntu下做开发,虚拟机要经常开启和关闭,重要的进程需要随机自启,非重要的可以手工启动.比如nginx就需要自启,confluence就没那么重要了. 为了控制哪些程序要自启,哪些程序不要 ...
- re2c实例
#include <stdio.h> #include "demo_def.h" #define T_BEGIN 0 #define T_NUMBER 1 #defin ...
- OAuth2.0 工作流程
重要术语 Authorization Server:授权服务器,能够成功验证资源拥有者和获取授权,并在此之后分发令牌的服务器: Resource Server:资源服务器,存储用户的数据资源,能够 ...
- Docker 安装及问题处理
1 确定Linux版本 uname -r 2 升级系统(添加 APT 镜像源,添加使用 HTTPS 传输的软件包以及 CA 证书.) sudo apt-get update sudo apt-get ...
- matlab imshow()函数显示白色图像问题
在MATLAB中,我们常使用imshow()函数来显示图像,而此时的图像矩阵可能经过了某种运算.在MATLAB中,为了保证精度,经过了运算的图像矩阵I其数据类型会从uint8型变成double型.如果 ...
- 快捷高效的cmd命令
经常在网上逛一些博客看一些技术文章,但是每每看过之后又忘记保存,或者东存一下,西存一下,到需要的时候回过头来,往往都找不到了.所以开通这个博客,把看到的好东西都记录下来,以便回头查看,也能与大家分享分 ...
- 实现koa中的generator用法
尽管koa2中已经被async/await代替.但我还是想自个儿着写一个koa1中的generator. 一, 写这个之前,先写一个可以现实,express中next用法的函数: var event= ...
- Ubuntu下NFS,TFTP服务搭建
环境:Ubuntu 一. 搭建NFS服务器 (1)安装: sudo apt-get install nfs-kernel-server #安装NFS服务器端 sudo apt-get instal ...