网络服务器软件开发/中间件开发,关注ACE/ICE/boost

C++博客 首页 新随笔 联系 聚合 管理
  152 Posts :: 3 Stories :: 172 Comments :: 0 Trackbacks
                                                                     作者:www.cppblog.com/true   2011年1月13日星期四            
      最近几天一直在思考一个问题:我们需要什么样的网络基础开发包?libevent,asio,ace,还是自己封装?每种选择都有他的理由,至于性能方面都差不多,因为都是对底层API的封装嘛,以前在linux下简单测试过libevent和ace的dev_poll_reactor,基本持平,现在代码没找到,有机会再做个全面对比。我现在比较关心这个问题:如何继承自己的内存池?按这个思路,libevent应该是不行了,没有这方面的接口;ace这个既臃肿又强大的东西肯定可以,不过他的ACE_Message_Block还是太复杂,不信的话,找一天时间看看他的代码,能搞懂他的成员函数不:),我上家公司的服务器平台都是基于ace的,版本是5.4,一直都很稳定,稳定归稳定,当时是花费了大量的时间的,以目前我的观察,越来越多的人不愿意接受这种几天也写不出代码的东西了。对于boost,我一直是若即若离,接触他是因为他的库可能出现在标准里面,抵触他是因为他的模板的使用,语法细节太多了,不直观。至少现在还没有让我不得不使用asio的理由。
      是否有必要使用内存池?也是见仁见智的问题,memcache是基于libevent开发的,没有内存池不是也一样很稳定吗?这个问题欢迎大家给出自己的看法

      下面是刚写的一个Buffer,有一些ace_message_block的影子,但语义有区别。

#ifndef BUFFER_H
#define BUFFER_H

#include 
<cstdlib>
#include 
<cstring>

class Buffer
{
public:
    
enum
    
{
        BUFFER_TYPE_DATA 
= 0x01,    //数据类型
        BUFFER_TYPE_CTRL = 0x02,    //控制类型
    }
;
    
enum 
    
{
        DEFAULT_BUFFER 
= 1024,
    }
;

    
explicit Buffer(size_t size = DEFAULT_BUFFER,int type = BUFFER_TYPE_DATA);
    
~Buffer();

    
//返回Buffer类型
    int        type();

    
//设置Buffer类型
    void    type(int t);

    
//返回存储空间起始指针
    char*    base();

    
//返回存储空间末端指针 + 1
    char*    end();

    
//返回未使用空间指针
    char*    ptr();

    
//移动数据块指针,如果pos大于0,ptr前移pos;如果pos<0,ptr后移|pos|
    void    ptr(int pos);

    
//复制数据,成功返回true,并且移动内部数据块指针;失败返回false
    bool    copy(const char* p,size_t n);

    
//返回实际数据块的大小
    size_t    size();

    
//返回分配的空间大小,包括未使用空间,space()的值大于等于size()
    size_t    space();

    
//返回数据块的总大小,即链表中数据块的大小之和
    size_t    totalSize();

    
//返回链表中的下一个Buffer指针
    Buffer*    next();

    
//设置下一个Buffer为buf
    void    next(Buffer* buf);

protected:
private:
    
int      type_;//Buffer类型
    char* base_;//指向数据块的起始位置
    char* ptr_;    //指向未使用空间
    size_t space_;//已经分配空间大小
    Buffer* next_;//指向的下一个Buffer
}
;


#endif


#include 
"Buffer.h"


Buffer::Buffer( size_t size 
/*= DEFAULT_BUFFER*/,int type /*= BUFFER_TYPE_DATA*/ )
{
    type_ 
= type;
    base_ 
=    (char*)malloc(size);
    memset(base_,
0,size);
    ptr_  
=    base_;
    space_ 
= size;
    next_ 
= NULL;
}

Buffer::
~Buffer()
{
    type_ 
= BUFFER_TYPE_DATA;
    free(base_);
    base_ 
= NULL;
    ptr_  
= NULL;
    space_ 
= 0;
    next_ 
= NULL;
}


int Buffer::type()
{
    
return type_;
}


void Buffer::type( int t )
{
    type_ 
= t;
}


char* Buffer::base()
{
    
return base_;
}


char* Buffer::end()
{
    
return base_ + space_;
}


bool Buffer::copy( const char* p,size_t n )
{
    
if (space() - size() >= n)
    
{
        memcpy(ptr(),p,n);
        ptr((
int)n);
        
return true;
    }

    
else
    
{
        
return false;
    }

}


size_t Buffer::size()
{
    
return ptr_ - base_;
}


size_t Buffer::space()
{
    
return space_;
}


char* Buffer::ptr()
{
    
return ptr_;
}


void Buffer::ptr( int pos )
{
    ptr_ 
+= pos;
}


Buffer
* Buffer::next()
{
    
return next_;
}


void Buffer::next( Buffer* buf )
{
    next_ 
= buf;
}


size_t Buffer::totalSize()
{
    size_t size 
= 0;
    
for (Buffer* p = this;p != NULL;p = p->next())
    
{
        size 
+= p->size();
    }

    
return size;
}


极为简陋且不完全的使用代码:

#include 
"../Base/Buffer.h"

int buffer_main(int argc, char* argv[])
{
    Buffer
* pBuf = new Buffer();

    
char* pStr = "hello";
    pBuf
->copy(pStr,strlen(pStr));

    size_t len 
= pBuf->size();
    size_t tlen 
= pBuf->totalSize();
    size_t slen 
= pBuf->space();
    delete pBuf;

    
return 0;
}

      TODO:内存池的实现

posted on 2011-01-13 00:51 true 阅读(3153) 评论(16)  编辑 收藏 引用 所属分类: ACE网络服务器开发

Feedback

# re: Buffer类就应该简单,直观 2011-01-13 09:21 expter
你这个Buffer只有Alloc没有free,
如果按照你这样设计free就悲剧了。  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-13 09:31 true
@expter
没太懂:(,本意是这样的:定长Buffer组成BufferList,构造中分配,析构中释放,在使用过程中不允许改变大小。  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-13 09:48 zuhd
这不就是传说中的对象池吗?
我觉得双向链表完全能代替之  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-13 11:54 finalday
个人觉得没必要有内存池这东西。
内存池不一定会比比直接new、delete高效。
这取决于具体应用。
不管3721直接把事情搞复杂化是过度设计的特征。  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-13 21:33 cd
我之前的服务器程序,各个系统负责自己的对象管理,当待用列表为空时,使用new申请一个对象。不使用一个对象时,放到待用列表。我觉得够用了  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-13 22:50 kasicass
对于基础网络库,如果是 message queue 的需求,可以参考下 www.zeromq.org。

简单的网络程序,libevent 足已。

是否需要对象池,如果需求固定、可测量,对象池有意义。
如果是通用的对象池(替代malloc/free),意义不大,glibc自带的已经不慢。win32下另当别论。  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-13 23:18 清正
问博主一个问题:
enum
{
BUFFER_TYPE_DATA = 0x01, //数据类型
BUFFER_TYPE_CTRL = 0x02, //控制类型
};
这里面 0x01 0x02是什么数据类型,
看到很多代码里都有类似描述,但是一直不明白这是什么。  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-14 00:52 bill gates
如果你认真看过asio的设计,那么你会发现要比他做得更好是比较困难的。  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-14 01:09 true
@finalday
@kasicass
考虑内存池倒不是运行时分配的效率问题,个人看重两方面:避免过多的动态分配,减少碎片;内存的可控性,容易避免内存泄露之类;对于一个服务器程序来说,他的数据包大小可以大致做一下划分,比如85%的数据包小于1K,那么这个1K就是内存池的基础大小,暂称为baseSize,另外确定数据包的maxSize,按照一定比例分配,这种方式可能会浪费一些内存,但我觉得够用了。  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-14 01:11 true
@清正
0x01是十六进制表示,二进制为0000 0001 :)  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-14 01:19 true
@bill gates
谢谢回复,找个时间阅读下asio的代码。如果是在公司没有基础库积累的情况下,让我选择,我可能会选择boost,不仅仅是因为asio,更多的是boost是一个all in one,比如正则,字符串处理,demo还提供了http,另外,asio有个值得称赞的地方是,proactor模型在linux是用epoll这种"本属于"reactor模型的api模拟的,这个做法实在是太考虑开发者感受了,用asio写的代码,无论win还是linux都是很高效。  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-14 01:34 清正
@true
谢谢 解惑, 那么 用16进制数据的作用是什么? 仅仅是因为范围表达的数据范围广泛吗?我想一般情况下 需要特别定义的数据应该不是很多, 为什么不直接用int表示呢  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-14 08:57 Benjamin
为什么不用模板?  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-14 09:36 true
@清正
十六进制更自然一些,
0x01
0x02
0x04
0x08
上面即可看出,用一个字节足以容下这个标记,而且有时存在对标记位的&或者|操作,这样的话,就不能再定义0x03了,因为0x03 == 0x01 + 0x02
  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-01-14 09:40 true
@Benjamin
我想保持足够简单,Buffer就是对原始内存的简陋封装。没明白Buffer类哪个地方需要模板,欢迎指正.  回复  更多评论
  

# re: Buffer类就应该简单,直观 2011-04-24 21:33 www
这种封装不要也罢~~  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理