libevent+多线程

最近在看memcached的源码,觉得它那种libevent+多线程的服务器模型真的很不错,我将这个模型封装成一个C++类,根据我的简单测试,这个模型的效率真的很不错,欢迎大家试用。

这个类的使用方法很简单(缺点是不太灵活),只要派生一个类,根据需要重写以下这几个虚函数就行了:

//新建连接成功后,会调用该函数
virtual void ConnectionEvent(Conn *conn) { }
//读取完数据后,会调用该函数
virtual void ReadEvent(Conn *conn) { } //发送完成功后,会调用该函数(因为串包的问题,所以并不是每次发送完数据都会被调用) virtual void WriteEvent(Conn *conn) { } //断开连接(客户自动断开或异常断开)后,会调用该函数 virtual void CloseEvent(Conn *conn, short events) { } //发生致命错误(如果创建子线程失败等)后,会调用该函数 //该函数的默认操作是输出错误提示,终止程序 virtual void ErrorQuit(const char *str);


如果大家有什么建议或意见,欢迎给我发邮件:aa1080711@163.com


上代码:

头文件:TcpEventServer.h

//TcpEventServer.h
#ifndef TCPEVENTSERVER_H_
#define TCPEVENTSERVER_H_

#include <stdio.h>
#include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <signal.h> #include <time.h> #include <pthread.h> #include <fcntl.h> #include <map> using std::map; #include <event.h> #include <event2/bufferevent.h> #include <event2/buffer.h> #include <event2/listener.h> #include <event2/util.h> #include <event2/event.h> class TcpEventServer; class Conn; class ConnQueue; struct LibeventThread; //这个类一个链表的结点类,结点里存储各个连接的信息, //并提供了读写数据的接口 class Conn {  //此类只能由TcpBaseServer创建,  //并由ConnQueue类管理  friend class ConnQueue;  friend class TcpEventServer; private:  const int m_fd; //socket的ID  evbuffer *m_ReadBuf; //读数据的缓冲区  evbuffer *m_WriteBuf; //写数据的缓冲区  Conn *m_Prev; //前一个结点的指针  Conn *m_Next; //后一个结点的指针  LibeventThread *m_Thread;  Conn(int fd=0);  ~Conn(); public:  LibeventThread *GetThread() { return m_Thread; }  int GetFd() { return m_fd; }  //获取可读数据的长度  int GetReadBufferLen()  { return evbuffer_get_length(m_ReadBuf); }  //从读缓冲区中取出len个字节的数据,存入buffer中,若不够,则读出所有数据  //返回读出数据的字节数  int GetReadBuffer(char *buffer, int len)  { return evbuffer_remove(m_ReadBuf, buffer, len); }  //从读缓冲区中复制出len个字节的数据,存入buffer中,若不够,则复制出所有数据  //返回复制出数据的字节数  //执行该操作后,数据还会留在缓冲区中,buffer中的数据只是原数据的副本  int CopyReadBuffer(char *buffer, int len)  { return evbuffer_copyout(m_ReadBuf, buffer, len); }  //获取可写数据的长度  int GetWriteBufferLen()  { return evbuffer_get_length(m_WriteBuf); }  //将数据加入写缓冲区,准备发送  int AddToWriteBuffer(char *buffer, int len)  { return evbuffer_add(m_WriteBuf, buffer, len); }  //将读缓冲区中的数据移动到写缓冲区  void MoveBufferData()  { evbuffer_add_buffer(m_WriteBuf, m_ReadBuf); } }; //带头尾结点的双链表类,每个结点存储一个连接的数据 class ConnQueue { private:  Conn *m_head;  Conn *m_tail; public:  ConnQueue();  ~ConnQueue();  Conn *InsertConn(int fd, LibeventThread *t);  void DeleteConn(Conn *c);  //void PrintQueue(); }; //每个子线程的线程信息 struct LibeventThread {  pthread_t tid; //线程的ID  struct event_base *base; //libevent的事件处理机  struct event notifyEvent; //监听管理的事件机  int notifyReceiveFd; //管理的接收端  int notifySendFd; //管道的发送端  ConnQueue connectQueue; //socket连接的链表  //在libevent的事件处理中要用到很多回调函数,不能使用类隐含的this指针  //所以用这样方式将TcpBaseServer的类指针传过去  TcpEventServer *tcpConnect; //TcpBaseServer类的指针 }; class TcpEventServer { private:  int m_ThreadCount; //子线程数  int m_Port; //监听的端口  LibeventThread *m_MainBase; //主线程的libevent事件处理机  LibeventThread *m_Threads; //存储各个子线程信息的数组  map<int, event*> m_SignalEvents; //自定义的信号处理 public:  static const int EXIT_CODE = -1; private:  //初始化子线程的数据  void SetupThread(LibeventThread *thread);  //子线程的入门函数  static void *WorkerLibevent(void *arg);  //(主线程收到请求后),对应子线程的处理函数  static void ThreadProcess(int fd, short which, void *arg);  //被libevent回调的各个静态函数  static void ListenerEventCb(evconnlistener *listener, evutil_socket_t fd,   sockaddr *sa, int socklen, void *user_data);  static void ReadEventCb(struct bufferevent *bev, void *data);  static void WriteEventCb(struct bufferevent *bev, void *data);  static void CloseEventCb(struct bufferevent *bev, short events, void *data); protected:  //这五个虚函数,一般是要被子类继承,并在其中处理具体业务的  //新建连接成功后,会调用该函数  virtual void ConnectionEvent(Conn *conn) { }  //读取完数据后,会调用该函数  virtual void ReadEvent(Conn *conn) { }  //发送完成功后,会调用该函数(因为串包的问题,所以并不是每次发送完数据都会被调用)  virtual void WriteEvent(Conn *conn) { }  //断开连接(客户自动断开或异常断开)后,会调用该函数  virtual void CloseEvent(Conn *conn, short events) { }  //发生致命错误(如果创建子线程失败等)后,会调用该函数  //该函数的默认操作是输出错误提示,终止程序  virtual 

转载于:https://www.cnblogs.com/wsswlyy/p/5557145.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值