ACE学习笔记--持续更新中
ACE_Asynch_Acceptor<Receiver> acceptor;
ACE_INET_Addr addr= ACE_INET_Addr("HAStatus");
if (acceptor.open (addr,
initial_read_size,
1) == -1)
return -1;
2.获得动态分配的端口号:
ACE_SOCK_SEQPACK_Association a=ACE_SOCK_SEQPACK_Association(acceptor.get_handle());
size_t addr_size=1;
a.get_local_addrs(&addr,addr_size);
ACE_DEBUG ((LM_DEBUG,"port:%d\n",addr.get_port_number()));
3.ACE在MFC中的使用
在程序运行之前调用 ACE::init();
在程序结束运行时调用 ACE::fini();
必须这样做,不然会出现通信不正常
4.ACE_InputCDR和ACE_OutputCDR字节错位的解决办法
ACE_OutputCDR out(mb);
如果out 了一个short再out一个long
out << (ACE_CDR::UShort)1;
out << (ACE_CDR::Long)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一个类型的数据时,输出流将自动按照这个输入类型的长度序对齐,如果没有对齐,则自动填充。
解决办法:
A.全部用一种类型,比如全部用ACE_CDR::ULong
B.打开ACE_ROOT/ace/config.h文件,加入以下一句
#define ACE_LACKS_CDR_ALIGNMENT
重新编译ACE,将新的lib加入工程
5.ACE与MFC混用时的内存泄漏
ACE 在MFC项目中存在内存泄露的问题主要是在ACE_Allocator内存分配器中,不过这个和ACE项目本身没什么问题,是MFC debug版本对new 和 delete操作做了一些处理,非MFC扩展DLL在MFC中都会出现这样的情况。如果你看这不舒服,我告诉你个最简单的方法解决这个问题。
第一、把项目中_AFXDLL编译开关去掉。
第二、把MDd改为MTd
6. 取得一个线程的执行时间效率
//定义开始时间
LARGE_INTEGER fre,star_,end_;
QueryPerformanceFrequency(&fre);
QueryPerformanceCounter(&star_);
// 处理....
pro( mb);
//得到结束的时间
QueryPerformanceCounter(&end_);
ACE_DEBUG((LM_INFO,ACE_TEXT(" (%t) 处理时间%i\n"),
long((end_.QuadPart - star_.QuadPart) * 10000 / fre.QuadPart)));
这个地方打印出来的时间是1个单位为0.1个毫秒
7.解决网络数据粘包的问题
数据粘包,就是取得的数据可能有不完整的包,也可能完整的包和不完整的包混杂在一起, 这里介绍如何将完整的包从中分解出来
一个网络上来的数据包之后,我们必需将收到的数据包整理成为一个一个的完成的数据包.这里写了一个代码来搞定这个问题的.
首先我们需要有一个内存缓冲区.还有我们已经使用了这个缓冲区的大小的标志.
void getData(const char* buff,int nSize)
{
char *pCheckBuff=(char*)buff; // 检查的缓冲区
int nCountSize=nSize; // 缓冲区的大小
bool bBuff=false; // 是否使用本地缓冲区
// 如果以前有断的数据包
if (nUsedSize_!=0)
{
memcpy(buf_+nUsedSize_,buff,nSize);
nUsedSize_+=nSize;
bBuff=true;
nCountSize=nUsedSize_;
}
// 开始对 pCheckBuff 内存块进行解包
// 当处理完成,或是数据包的长度没有这么长的时候退出
int offset=0;
int leave=nCountSize;
while (1)
{
leave=nCountSize-offset;
// 得到数据包头
if (leave>DATA_HEAD_SIZE)
{
DataHead* pHead=(DataHead*)pCheckBuff+offset;
// 检查数据包是否正确
if (check_head(pHead))
{
// 检查数据体是否完整
if (pHead->nSize<=leave)
{
ACE_Message_Block *new_mb = blockTash_.get_free_block();
new_mb->copy(pCheckBuff+offset,pHead->nSize);
//new_mb->wr_ptr(pHead->nSize);
((Acceptor*)pAcceptor_)->on_user_data(this->nIndex_,*new_mb,pHead->nSize);
//
// ((Acceptor*)pAcceptor_)->on_user_data(this->nIndex_,mb,result.bytes_transferred ());
offset+=pHead->nSize;
}
// 不完整的数据包
else
{
goto lable1;
}
}
// 错误的数据包.将把这一次的数据全部丢失
else
{
nUsedSize_=0;
leave=0;
break;
}
}
// 没有完整的数据包头
else
{
goto lable1;
}
}
return ;
// 保存数据
// 移动缓冲区的数据
lable1:
// 在本地的缓冲区中
if (leave!=0)
{
memcpy(buf_,pCheckBuff+offset,leave);
nUsedSize_=leave;
}
return ;
}
8.使用ACE_Task的时候要留意putq函数
在使用ACE_Task的时候,可以把这个对象看成一个处理器对象,他有一个消息队列,有一堆的线程在处理这一个消息。所以在应用中使用这个东西的机会特别的多。这次我使用的时候发现一个这样的问题。如果数据的速度太快了的时候将会使调用putq函数调用不成功。
这是一个例子代码,其实每一个Task都聚集了一个msg_queue对象的指针,他有一个参数:high_water_mark,就是说,在这个队列中的每个元素的size之和的最高。他的默认值是1024*16。但是有可能还是被占满了。如果发现putq不成功的时候就要使用这个东西来调整水位了。
int ACE_TMAIN(int, ACE_TCHAR *[])
{
MyTask task;
task.star();
task.msg_queue_->high_water_mark(16385);
ACE_Message_Block *new1=new ACE_Message_Block(16384);
task.putq(new1);
new1=new ACE_Message_Block(1);
ACE_Time_Value tv(0,1000);
if (task.putq(new1,&tv)==-1)
{
cout<<"put时失败"<<endl;
}
getchar();
return 0;
}