基于libevent的多线程通信框架实现

  很久没有写博客了,这半年多时间一直很忙,一直没有更新博客,今天心血来潮准备做一篇,刚好把最近的新研究东西拿出来给大家分享一下!自己以前的一个后台程序框架(应用于了很多应用项目,运营商***拦截系统,国内某视频聊天应用的后台系统等),里面的网络部分基于ACE来实现的,最近准备淘汰ACE,大部分组件功能打算重写,所以基于网络这块打算用libevent来实现,在做的过程中发现了一些问题,就是能找到的例子都是单线程实现的,有多线的例子也没有写得那么详细,都是很简单的实现,经过一周时间对源码和api的分析,自己做了实现,经过测试还没有发现问题,效率上比之前的框架做了很大的提升,今天给大家贴出来,做分享交流。

NetFrame.h

[cpp]   view plain  copy
  1. //  
  2. //  NetFrame.h  
  3. //  Frame  
  4. //  
  5. //  Created by chenjianjun on 15/9/7.  
  6. //  Copyright (c) 2015年 jsbn. All rights reserved.  
  7. //  
  8.   
  9. #ifndef __Frame__NetFrame__  
  10. #define __Frame__NetFrame__  
  11.   
  12. #include <event.h>  
  13. #include <glog/logging.h>  
  14. #include "Common.h"  
  15. #include "Thread.h"  
  16.   
  17. namespace NAME_SPACE {  
  18.       
  19.     class NetFrame {  
  20.           
  21.     public:  
  22.         static NetFrame* Instance();  
  23.         int NetWorkInit();  
  24.         int NetWorkExit();  
  25.           
  26.     protected:  
  27.         NetFrame();  
  28.         ~NetFrame();  
  29.           
  30.     private:  
  31.         class NetRunnable:public Runnable {  
  32.               
  33.         public:  
  34.             NetRunnable();  
  35.             ~NetRunnable();  
  36.               
  37.         protected:  
  38.             virtual void Run(void*);  
  39.         };  
  40.           
  41.         friend class NetRunnable;  
  42.         DISALLOW_EVIL_CONSTRUCTORS(NetFrame);  
  43.       
  44.     public:  
  45.         static struct event_base* _base;  
  46.           
  47.     private:  
  48.         Thread _main_loop_thread;  
  49.         volatile bool _run_flg;  
  50.         NetRunnable _runnable;  
  51.     };  
  52.       
  53. }  
  54.   
  55. #endif /* defined(__Frame__NetFrame__) */  

NetFrame.cpp
[cpp]   view plain  copy
  1. //  
  2. //  NetFrame.cpp  
  3. //  Frame  
  4. //  
  5. //  Created by chenjianjun on 15/9/7.  
  6. //  Copyright (c) 2015年 jsbn. All rights reserved.  
  7. //  
  8. #include "NetFrame.h"  
  9. #include <event2/event.h>  
  10.   
  11. namespace NAME_SPACE {  
  12.       
  13.     struct event_base* NetFrame::_base = nullptr;  
  14.       
  15.     NetFrame* NetFrame::Instance() {  
  16.         LIBJINGLE_DEFINE_STATIC_LOCAL(NetFrame, manager, ());  
  17.         return &manager;  
  18.     }  
  19.       
  20.     NetFrame::NetFrame():_run_flg(false){}  
  21.       
  22.     NetFrame::~NetFrame(){  
  23.         NetWorkExit();  
  24.     }  
  25.       
  26.     NetFrame::NetRunnable::NetRunnable() {}  
  27.     NetFrame::NetRunnable::~NetRunnable() {}  
  28.       
  29.     void NetFrame::NetRunnable::Run(void* arg) {  
  30.           
  31.         NetFrame* pNetFrame = (NetFrame*)arg;  
  32.         while (pNetFrame->_run_flg) {  
  33.             Thread::SleepMs(2000);  
  34.             event_base_dispatch(NetFrame::_base);  
  35.         }  
  36.     }  
  37.       
  38.     int NetFrame::NetWorkInit() {  
  39.           
  40.         if (_run_flg) {  
  41.             return FUNC_SUCCESS;  
  42.         }  
  43.           
  44.         evthread_use_pthreads();  
  45.         _base = event_base_new();  
  46.         evthread_make_base_notifiable(_base);  
  47.   
  48.         // 开启事件监听主线程  
  49.         _run_flg = true;  
  50.         if (_main_loop_thread.Start(&_runnable, this)) {  
  51.             return FUNC_SUCCESS;  
  52.         }  
  53.           
  54.         // 开始线程失败置运行标志  
  55.         _run_flg = false;  
  56.           
  57.         return FUNC_FAILED;  
  58.     }  
  59.       
  60.     int NetFrame::NetWorkExit() {  
  61.           
  62.         if (!_run_flg) {  
  63.             return FUNC_SUCCESS;  
  64.         }  
  65.           
  66.         _run_flg = false;  
  67.         event_base_loopexit(NetFrame::_base, nullptr);  
  68.         _main_loop_thread.Stop();  
  69.         event_base_free(_base);  
  70.         _base = nullptr;  
  71.           
  72.         return FUNC_SUCCESS;  
  73.     }  
  74. }  

服务器对象类

ServerWorker.h

[cpp]   view plain  copy
  1. //  
  2. //  ServerWorker.h  
  3. //  服务器对象类  
  4. //  
  5. //  Created by chenjianjun on 15/9/7.  
  6. //  Copyright (c) 2015年 jsbn. All rights reserved.  
  7. //  
  8.   
  9. #ifndef __ServerWorker_H_  
  10. #define __ServerWorker_H_  
  11.   
  12. #include <string>  
  13. #include <event2/listener.h>  
  14. #include "NetSignal.h"  
  15.   
  16. namespace NAME_SPACE {  
  17.       
  18.     class ServerWorker {  
  19.           
  20.     public:  
  21.         /** 
  22.          *  @brief  服务器构造函数 
  23.          * 
  24.          *  @param  listen_ip   监听的本地IP 
  25.          *  @param  listen_port 监听的本地端口 
  26.          * 
  27.          *  @return 
  28.          */  
  29.         ServerWorker(std::string listen_ip, int listen_port);  
  30.         ServerWorker(int listen_port);  
  31.           
  32.         ~ServerWorker();  
  33.           
  34.         /** 
  35.          *  @brief  启动工作 
  36.          * 
  37.          *  @param 
  38.          * 
  39.          *  @return 
  40.          */  
  41.         bool StartWork(TCPServerSignal* pTCPServerSignal);  
  42.           
  43.         /** 
  44.          *  @brief  停止工作 
  45.          * 
  46.          *  @param 
  47.          * 
  48.          *  @return 
  49.          */  
  50.         void StopWork();  
  51.           
  52.         // 获取监听套接字  
  53.         SOCKET GetFd() { return _listen_fd; }  
  54.           
  55.     public:  
  56.           
  57.         /** 
  58.          *  @brief  新连接处理,此函数外部禁止调用,用于event事件回调函数调用 
  59.          * 
  60.          *  @param  int 套接字句柄 
  61.          *  @param  struct sockaddr_in * 客户端地址 
  62.          */  
  63.         void Accept(int fd, struct sockaddr_in *sa);  
  64.           
  65.         /** 
  66.          *  @brief  监听失败事件处理,此函数外部禁止调用,用于event事件回调函数调用 
  67.          * 
  68.          *  @param  int 套接字句柄 
  69.          *  @param  EM_NET_EVENT 错误码 
  70.          */  
  71.         void AcceptError(int fd, EM_NET_EVENT msg);  
  72.           
  73.     private:  
  74.         // 事件监听器  
  75.         evconnlistener* _listener;  
  76.         // 监听的IP  
  77.         std::string _listen_ip;  
  78.         // 监听的端口  
  79.         unsigned short _listen_port;  
  80.         // 监听的套接字  
  81.         SOCKET _listen_fd;  
  82.         // 连接器  
  83.         TCPServerSignal* _pTCPServerSignal;  
  84.     };  
  85.       
  86. }  
  87.   
  88. #endif /* defined(__ServerWorker_H_) */  

ServerWorker.cpp
[cpp]   view plain  copy
  1. //  
  2. //  ServerWorker.cpp  
  3. //  Frame  
  4. //  
  5. //  Created by chenjianjun on 15/9/7.  
  6. //  Copyright (c) 2015年 jsbn. All rights reserved.  
  7. //  
  8.   
  9. #include "ServerWorker.h"  
  10. #include "NetFrame.h"  
  11.   
  12. namespace NAME_SPACE {  
  13.       
  14.     // 客户端连接事件回调处理函数  
  15.     static void ListenerEventCb(evconnlistener *listener, evutil_socket_t fd,  
  16.                                 sockaddr *sa, int socklen, void *user_data) {  
  17.         ServerWorker *pServerWorker = (ServerWorker*)user_data;  
  18.         struct linger l;  
  19.         l.l_onoff = 1;  
  20.         l.l_linger = 0;  
  21.         setsockopt(fd, SOL_SOCKET, SO_LINGER, (void*)&l, sizeof(l));  
  22.         pServerWorker->Accept(fd, (struct sockaddr_in *)sa);  
  23.     }  
  24.       
  25.     // 监听失败回调处理函数  
  26.     static void ListenerErrorCb(struct evconnlistener *listener, void *user_data) {  
  27.         ServerWorker* pServerWorker = (ServerWorker*)user_data;  
  28.         pServerWorker->AcceptError(pServerWorker->GetFd(),ENE_ACCEPT_ERROR);  
  29.                                    //evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));  
  30.     }  
  31.       
  32.     ServerWorker::ServerWorker(std::string listen_ip, int listen_port)  
  33.     :_listen_ip(listen_ip),  
  34.     _listen_port(listen_port),  
  35.     _listener(nullptr),  
  36.     _pTCPServerSignal(nullptr) {}  
  37.       
  38.     ServerWorker::ServerWorker(int listen_port)  
  39.     :_listen_port(listen_port),  
  40.     _listener(nullptr),  
  41.     _pTCPServerSignal(nullptr) {  
  42.         _listen_ip.clear();  
  43.     }  
  44.       
  45.     bool ServerWorker::StartWork(TCPServerSignal* pTCPServerSignal) {  
  46.           
  47.         if (_listener) {  
  48.             return false;  
  49.         }  
  50.           
  51.         sockaddr_in sin;  
  52.         memset(&sin, 0, sizeof(sin));  
  53.         sin.sin_family = AF_INET;  
  54.         if (!_listen_ip.empty()) { sin.sin_addr.s_addr = ::inet_addr(_listen_ip.c_str()); }  
  55.         sin.sin_port = htons(_listen_port);  
  56.           
  57.         _listener = evconnlistener_new_bind(NetFrame::_base,  
  58.                                             ListenerEventCb,  
  59.                                             (void*)this,  
  60.                                             LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,  
  61.                                             -1,  
  62.                                             (sockaddr*)&sin,  
  63.                                             sizeof(sockaddr_in));  
  64.         if( nullptr == _listener ) {  
  65.             LOG(ERROR)<<"创建监听器失败,IP["<<_listen_ip<<":"<<_listen_port<<"]";  
  66.             return false;  
  67.         }  
  68.           
  69.         _pTCPServerSignal = pTCPServerSignal;  
  70.           
  71.         // 设置监听失败回调  
  72.         evconnlistener_set_error_cb(_listener, ListenerErrorCb);  
  73.           
  74.         // 获取监听的套接字句柄  
  75.         _listen_fd = evconnlistener_get_fd(_listener);  
  76.           
  77.         return true;  
  78.     }  
  79.       
  80.     void ServerWorker::StopWork()  
  81.     {  
  82.         if (_listener) {  
  83.             evconnlistener_free(_listener);  
  84.             _listener = nullptr;  
  85.         }  
  86.     }  
  87.       
  88.     void ServerWorker::Accept(int fd, struct sockaddr_in *sa) {  
  89.         if (_pTCPServerSignal) {  
  90.             _pTCPServerSignal->SignalAccept(fd, sa);  
  91.         }  
  92.     }  
  93.       
  94.     void ServerWorker::AcceptError(int fd, EM_NET_EVENT msg) {  
  95.         if (_pTCPServerSignal) {  
  96.             _pTCPServerSignal->SignalAcceptError(fd, msg);  
  97.         }  
  98.     }  
  99.       
  100. }  

被动客户端连接类

PassiveTCPClient.h

[cpp]   view plain  copy
  1. //  
  2. //  PassiveTCPClient.h  
  3. //  Frame  
  4. //  
  5. //  Created by chenjianjun on 15/9/7.  
  6. //  Copyright (c) 2015年 jsbn. All rights reserved.  
  7. //  
  8.   
  9. #ifndef __PassiveTCPClient_H_  
  10. #define __PassiveTCPClient_H_  
  11.   
  12. #include <string>  
  13. #include <event.h>  
  14. #include <event2/listener.h>  
  15. #include "NetSignal.h"  
  16.   
  17. namespace NAME_SPACE {  
  18.       
  19.     class PassiveTCPClient {  
  20.           
  21.     public:  
  22.         /** 
  23.          *  @brief  构造函数 
  24.          * 
  25.          *  @param  SOCKET 套接字句柄 
  26.          *  @param  sockaddr_in* 客户端地址 
  27.          *  @param  short 心跳时间 
  28.          * 
  29.          *  @return 
  30.          */  
  31.         PassiveTCPClient(SOCKET fd, struct sockaddr_in* sa, short heart_time = 10);  
  32.         ~PassiveTCPClient();  
  33.           
  34.         /** 
  35.          *  @brief  启动工作 
  36.          * 
  37.          *  @param 
  38.          * 
  39.          *  @return 
  40.          */  
  41.         bool StartWork(TCPClientSignal*);  
  42.           
  43.         /** 
  44.          *  @brief  停止工作 
  45.          * 
  46.          *  @param 
  47.          * 
  48.          *  @return 
  49.          */  
  50.         void StopWork();  
  51.           
  52.         /** 
  53.          *  @brief  发送数据 
  54.          * 
  55.          *  @paramv char* 数据 
  56.          *  @paramv size_t 数据长度 
  57.          * 
  58.          *  @return 
  59.          */  
  60.         int SendData(void* pdata, size_t len);  
  61.           
  62.         SOCKET GetFd() { return _fd; }  
  63.         void SetHeartFlg(bool flg) { _heart_flg = flg; }  
  64.         bool GetHeartFlg() { return _heart_flg; }  
  65.           
  66.     public:  
  67.           
  68.         /** 
  69.          *  @brief  接收数据,此函数外部禁止调用,用于event事件回调函数调用 
  70.          * 
  71.          *  @param  void* 数据 
  72.          *  @param  size_t 数据长度 
  73.          */  
  74.         void PutRecvData(void*, size_t);  
  75.   
  76.         /** 
  77.          *  @brief  事件处理,此函数外部禁止调用,用于event事件回调函数调用 
  78.          * 
  79.          *  @param  short 事件集合 
  80.          */  
  81.         void ProcEvent(short events);  
  82.           
  83.     public:  
  84.         /* 
  85.          连接器类,这个分离很重要,如果不分离会出现小概率崩溃现象,主要是连接函数在调用的时候回调函数里面, 
  86.          如果外部删除这个对象会出现内存访问异常,具体看实现(那里是一个自动锁实现,崩溃也在自动锁释放那里) 
  87.          */  
  88.         TCPClientSignal* _pTCPClientSignal;  
  89.   
  90.     private:  
  91.         // 客户端IP  
  92.         std::string _client_ip;  
  93.         // 客户端端口  
  94.         unsigned short _client_port;  
  95.         // 套接字句柄  
  96.         SOCKET _fd;  
  97.         // 心跳时间  
  98.         short _heart_time;  
  99.         // bufferevent  
  100.         struct bufferevent *_bev;  
  101.         // 心跳事件器  
  102.         struct event *_event;  
  103.         // 心跳标志  
  104.         volatile bool _heart_flg;  
  105.     };  
  106.       
  107. }  
  108.   
  109. #endif /* defined(__PassiveTCPClient_H_) */  

PassiveTCPClient.cpp
[cpp]   view plain  copy
  1. //  
  2. //  PassiveTCPClient.cpp  
  3. //  被动TCP客户端  
  4. //  
  5. //  Created by chenjianjun on 15/9/7.  
  6. //  Copyright (c) 2015年 jsbn. All rights reserved.  
  7. //  
  8.   
  9. #include "PassiveTCPClient.h"  
  10. #include "NetFrame.h"  
  11.   
  12. namespace NAME_SPACE {  
  13.       
  14.     void PassiveTCPTimeOutEventCb(evutil_socket_t fd, shortvoid *data) {  
  15.           
  16.         PassiveTCPClient *pPassiveTCPClient = (PassiveTCPClient*)data;  
  17.         if (pPassiveTCPClient->GetHeartFlg()) {  
  18.             // 超时清除标志  
  19.             pPassiveTCPClient->SetHeartFlg(false);  
  20.         } else {  
  21.             // 心跳超时回调  
  22.             pPassiveTCPClient->ProcEvent(BEV_EVENT_TIMEOUT);  
  23.         }  
  24.     }  
  25.       
  26.     void PassiveTCPReadEventCb(struct bufferevent *bev, void *data) {  
  27.           
  28.         PassiveTCPClient* pPassiveTCPClient = (PassiveTCPClient*)data;  
  29.           
  30.         static char databuf[40960];  
  31.         size_t datalen = 0;  
  32.         size_t nbytes;  
  33.           
  34.         while ((nbytes = evbuffer_get_length(bev->input)) > 0) {  
  35.             evbuffer_remove(bev->input, databuf+datalen, sizeof(databuf)-datalen);  
  36.             datalen += nbytes;  
  37.         }  
  38.           
  39.         // 有数据往来,设置标志  
  40.         pPassiveTCPClient->SetHeartFlg(true);  
  41.           
  42.         // 数据接收回调  
  43.         pPassiveTCPClient->PutRecvData(databuf, datalen);  
  44.     }  
  45.       
  46.     void PassiveTCPEventCb(struct bufferevent *bev, short events, void *data) {  
  47.           
  48.         PassiveTCPClient* pPassiveTCPClient = (PassiveTCPClient*)data;  
  49.           
  50.         // 处理事件  
  51.         pPassiveTCPClient->ProcEvent(events);  
  52.     }  
  53.       
  54.     PassiveTCPClient::PassiveTCPClient(SOCKET fd, struct sockaddr_in* sa, short heart_time)  
  55.     :_fd(fd),  
  56.     _client_ip(inet_ntoa(sa->sin_addr)),  
  57.     _client_port(ntohs(sa->sin_port)),  
  58.     _bev(nullptr),  
  59.     _heart_flg(false),  
  60.     _heart_time(heart_time),  
  61.     _pTCPClientSignal(nullptr)  
  62.     {}  
  63.       
  64.     PassiveTCPClient::~PassiveTCPClient() {  
  65.         StopWork();  
  66.         _pTCPClientSignal = nullptr;  
  67.     }  
  68.       
  69.     bool PassiveTCPClient::StartWork(TCPClientSignal* pTCPClientSignal) {  
  70.           
  71.         if (_bev) {  
  72.             return false;  
  73.         }  
  74.           
  75.         _bev = bufferevent_socket_new(NetFrame::_base,  
  76.                                       _fd,  
  77.                                       BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);  
  78.         if (_bev == nullptr) {  
  79.             return false;  
  80.         }  
  81.           
  82.         _event = event_new(NetFrame::_base,  
  83.                            _fd,  
  84.                            EV_TIMEOUT|EV_PERSIST,  
  85.                            PassiveTCPTimeOutEventCb, this);  
  86.         if (_event == nullptr) {  
  87.             bufferevent_free(_bev);  
  88.             _bev = nullptr;  
  89.             return false;  
  90.         }  
  91.           
  92.         _pTCPClientSignal = pTCPClientSignal;  
  93.         // 设置心跳检测时间  
  94.         struct timeval timeout = {_heart_time, 0};  
  95.         event_add(_event, &timeout);  
  96.           
  97.         bufferevent_setcb(_bev, PassiveTCPReadEventCb, nullptr, PassiveTCPEventCb, this);  
  98.         bufferevent_enable(_bev, EV_READ);  
  99.           
  100.         return true;  
  101.     }  
  102.       
  103.     void PassiveTCPClient::StopWork() {  
  104.           
  105.         if (_bev) {  
  106.             bufferevent_disable(_bev, EV_READ);  
  107.             bufferevent_free(_bev);  
  108.             _bev = nullptr;  
  109.         }  
  110.           
  111.         if (_event) {  
  112.             event_del(_event);  
  113.             event_free(_event);  
  114.             _event = nullptr;  
  115.         }  
  116.           
  117.         // 不要对_pPassiveTCPClientSignal置null,释放由外部传入者负责  
  118.     }  
  119.       
  120.     int PassiveTCPClient::SendData(void* pdata, size_t len) {  
  121.           
  122.         if (_bev == nullptr) {  
  123.             return FUNC_FAILED;  
  124.         }  
  125.   
  126.         if (bufferevent_write(_bev, pdata, len) < 0) {  
  127.             return FUNC_FAILED;  
  128.         }  
  129.           
  130.         return FUNC_SUCCESS;  
  131.     }  
  132.       
  133.     void PassiveTCPClient::PutRecvData(void* data, size_t len) {  
  134.           
  135.         if (_pTCPClientSignal) {  
  136.             _pTCPClientSignal->SignalRecvData(_fd, data, len);  
  137.         }  
  138.     }  
  139.       
  140.     void PassiveTCPClient::ProcEvent(short events) {  
  141.           
  142.         if (!_pTCPClientSignal) {  
  143.             return;  
  144.         }  
  145.           
  146.         if (events & BEV_EVENT_CONNECTED) {  
  147.             _pTCPClientSignal->SignalEvent(_fd, ENE_CONNECTED);  
  148.         }  
  149.           
  150.         if(events & (BEV_EVENT_READING | BEV_EVENT_WRITING | BEV_EVENT_EOF | BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT))  
  151.         {  
  152.              _pTCPClientSignal->SignalEvent(_fd, ENE_CLOSE);  
  153.         }  
  154.           
  155.     }  
  156. }  

主动客户端连接类

ActiveTCPClient.h

[cpp]   view plain  copy
  1. //  
  2. //  ActiveTCPClient.h  
  3. //  Frame 主动TCP客户端连接类  
  4. //  
  5. //  Created by chenjianjun on 15/9/8.  
  6. //  Copyright (c) 2015年 jsbn. All rights reserved.  
  7. //  
  8.   
  9. #ifndef __ActiveTCPClient_H_  
  10. #define __ActiveTCPClient_H_  
  11.   
  12. #include <string>  
  13. #include <event.h>  
  14. #include "NetSignal.h"  
  15. #include "RWLock.h"  
  16.   
  17. namespace NAME_SPACE {  
  18.       
  19.     class ActiveTCPClient {  
  20.           
  21.     public:  
  22.         explicit ActiveTCPClient(std::string host_name,  
  23.                                  unsigned short host_port,  
  24.                                  short heart_time = 10);  
  25.           
  26.         ~ActiveTCPClient();  
  27.           
  28.         void SetTCPClientSignal(TCPClientSignal* pTCPClientSignal) { _pTCPClientSignal = pTCPClientSignal;}  
  29.         /** 
  30.          *  @brief  启动工作 
  31.          * 
  32.          *  @param 
  33.          * 
  34.          *  @return 
  35.          */  
  36.         bool StartWork();  
  37.           
  38.         /** 
  39.          *  @brief  停止工作 
  40.          * 
  41.          *  @param 
  42.          * 
  43.          *  @return 
  44.          */  
  45.         void StopWork();  
  46.           
  47.         /** 
  48.          *  @brief  发送数据 
  49.          * 
  50.          *  @paramv char* 数据 
  51.          *  @paramv size_t 数据长度 
  52.          * 
  53.          *  @return 
  54.          */  
  55.         int SendData(void* pdata, size_t len);  
  56.           
  57.         SOCKET GetFd() { return _fd; }  
  58.         void SetHeartFlg(bool flg) { _heart_flg = flg; }  
  59.         bool GetHeartFlg() { return _heart_flg; }  
  60.         bool IsConnect() { return _connect_flg == 2;}  
  61.           
  62.     public:  
  63.         /** 
  64.          *  @brief  接收数据,此函数外部禁止调用,用于event事件回调函数调用 
  65.          * 
  66.          *  @param  void* 数据 
  67.          *  @param  size_t 数据长度 
  68.          */  
  69.         void PutRecvData(void*, size_t);  
  70.           
  71.         /** 
  72.          *  @brief  事件处理,此函数外部禁止调用,用于event事件回调函数调用 
  73.          * 
  74.          *  @param  short 事件集合 
  75.          */  
  76.         void ProcEvent(short events);  
  77.           
  78.     public:  
  79.         /* 
  80.          连接器类,这个分离很重要,如果不分离会出现小概率崩溃现象,主要是连接函数在调用的时候回调函数里面, 
  81.          如果外部删除这个对象会出现内存访问异常,具体看实现(那里是一个自动锁实现,崩溃也在自动锁释放那里) 
  82.          */  
  83.         TCPClientSignal* _pTCPClientSignal;  
  84.           
  85.     private:  
  86.         // 服务器监听地址  
  87.         std::string _host_name;  
  88.         // 服务器监听端口  
  89.         unsigned short _host_port;  
  90.         // bufferevent  
  91.         struct bufferevent *_bev;  
  92.         // 心跳检测时间  
  93.         short _heart_time;  
  94.         // socket连接句柄  
  95.         SOCKET _fd;  
  96.         // 心跳事件器  
  97.         struct event *_event;  
  98.         // 心跳标志  
  99.         volatile bool _heart_flg;  
  100.         // 读写锁  
  101.         RWLock* _m_rw_loacl;  
  102.         // 连接标志 0:未连接 1:连接中 2:已连接  
  103.         volatile unsigned char _connect_flg;  
  104.     };  
  105.       
  106. }  
  107.   
  108. #endif /* defined(__ActiveTCPClient_H_) */  

ActiveTCPClient.cpp
[cpp]   view plain  copy
  1. //  
  2. //  ActiveTCPClient.cpp  
  3. //  Frame  
  4. //  
  5. //  Created by chenjianjun on 15/9/8.  
  6. //  Copyright (c) 2015年 jsbn. All rights reserved.  
  7. //  
  8.   
  9. #include "ActiveTCPClient.h"  
  10. #include "NetFrame.h"  
  11.   
  12. namespace NAME_SPACE {  
  13.       
  14.     void ActiveTCPTimeOutEventCb(evutil_socket_t fd, shortvoid *data) {  
  15.         ActiveTCPClient* pActiveTCPClient = (ActiveTCPClient*)data;  
  16.         pActiveTCPClient->ProcEvent(BEV_EVENT_TIMEOUT);  
  17.     }  
  18.       
  19.     void ActiveTCPEventCb(struct bufferevent *bev, short events, void *data) {  
  20.         ActiveTCPClient* pActiveTCPClient = (ActiveTCPClient*)data;  
  21.         pActiveTCPClient->ProcEvent(events);  
  22.     }  
  23.       
  24.     void ActiveTCPReadEventCb(struct bufferevent *bev, void *data) {  
  25.           
  26.         ActiveTCPClient* pActiveTCPClient = (ActiveTCPClient*)data;  
  27.           
  28.         static char databuf[40960];  
  29.         size_t datalen = 0;  
  30.         size_t nbytes;  
  31.           
  32.         while ((nbytes = evbuffer_get_length(bev->input)) > 0) {  
  33.             evbuffer_remove(bev->input, databuf+datalen, sizeof(databuf)-datalen);  
  34.             datalen += nbytes;  
  35.         }  
  36.           
  37.         // 有数据往来,设置标志  
  38.         pActiveTCPClient->SetHeartFlg(true);  
  39.           
  40.         // 数据接收回调  
  41.         pActiveTCPClient->PutRecvData(databuf, datalen);  
  42.           
  43.     }  
  44.       
  45.     ActiveTCPClient::ActiveTCPClient(std::string host_name, unsigned short host_port, short heart_time)  
  46.     :_host_name(host_name),  
  47.     _host_port(host_port),  
  48.     _heart_time(heart_time),  
  49.     _bev(nullptr),  
  50.     _pTCPClientSignal(nullptr),  
  51.     _heart_flg(false),  
  52.     _event(nullptr),  
  53.     _connect_flg(0),  
  54.     _m_rw_loacl(RWLock::Create()) {  
  55.     }  
  56.       
  57.     ActiveTCPClient::~ActiveTCPClient() {  
  58.         StopWork();  
  59.         _pTCPClientSignal = nullptr;  
  60.         delete _m_rw_loacl;  
  61.     }  
  62.       
  63.     bool ActiveTCPClient::StartWork() {  
  64.           
  65.         WriteLockScoped wLock(*_m_rw_loacl);  
  66.           
  67.         if (_bev) {  
  68.             return false;  
  69.         }  
  70.           
  71.         _fd = socket(AF_INET, SOCK_STREAM, 0);  
  72.         evutil_make_socket_nonblocking(_fd);  
  73.         if (_fd < 0) {  
  74.             return false;  
  75.         }  
  76.           
  77.         _bev = bufferevent_socket_new(NetFrame::_base, _fd, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);  
  78.         if (_bev == nullptr) {  
  79.             close(_fd);  
  80.             return false;  
  81.         }  
  82.           
  83.         struct sockaddr_in sSvrAddr;  
  84.         memset(&sSvrAddr, 0, sizeof(sSvrAddr));  
  85.         sSvrAddr.sin_family = AF_INET;  
  86.         sSvrAddr.sin_addr.s_addr = inet_addr(_host_name.c_str());  
  87.         sSvrAddr.sin_port = htons(_host_port);  
  88.         int addrlen = sizeof(struct sockaddr_in);  
  89.           
  90.         // 置为连接中状态  
  91.         _connect_flg = 1;  
  92.         if (bufferevent_socket_connect(_bev, (struct sockaddr*)&sSvrAddr, addrlen) < 0) {  
  93.             _connect_flg = 0;  
  94.             StopWork();  
  95.             return false;  
  96.         }  
  97.           
  98.         bufferevent_setcb(_bev, ActiveTCPReadEventCb, nullptr, ActiveTCPEventCb, this);  
  99.         bufferevent_enable(_bev, EV_READ);  
  100.           
  101.         return true;  
  102.     }  
  103.       
  104.     void ActiveTCPClient::StopWork() {  
  105.           
  106.         WriteLockScoped wLock(*_m_rw_loacl);  
  107.           
  108.         _connect_flg = 0;  
  109.         if (_event) {  
  110.             event_del(_event);  
  111.             event_free(_event);  
  112.             _event = nullptr;  
  113.         }  
  114.           
  115.         if (_bev) {  
  116.             bufferevent_disable(_bev, EV_READ);  
  117.             bufferevent_free(_bev);  
  118.             _bev = nullptr;  
  119.             _fd = -1;  
  120.         }  
  121.     }  
  122.       
  123.     int ActiveTCPClient::SendData(void* pdata, size_t len) {  
  124.           
  125.         LOG(INFO)<<"发送数据1..........";  
  126.         ReadLockScoped rLock(*_m_rw_loacl);  
  127.           
  128.         if (_bev == nullptr || _connect_flg != 2) {  
  129.             return FUNC_FAILED;  
  130.         }  
  131.   
  132.         if (bufferevent_write(_bev, pdata, len) < 0) {  
  133.             return FUNC_FAILED;  
  134.         }  
  135.           
  136. //        if (send(_fd, pdata, len, 0) < 0) {  
  137. //            return FUNC_FAILED;  
  138. //        }  
  139.           
  140.         LOG(INFO)<<"发送数据32..........";  
  141.           
  142.         return FUNC_SUCCESS;  
  143.           
  144.     }  
  145.       
  146.     void ActiveTCPClient::ProcEvent(short events) {  
  147.           
  148.         if (!_pTCPClientSignal) {  
  149.             return;  
  150.         }  
  151.           
  152.         if (events & BEV_EVENT_CONNECTED) {  
  153.               
  154.             // 已连接状态  
  155.             _connect_flg = 2;  
  156.             // 连接建立,开启心跳计数  
  157.             _event = event_new(NetFrame::_base,  
  158.                                _fd,  
  159.                                EV_TIMEOUT|EV_PERSIST,  
  160.                                ActiveTCPTimeOutEventCb,  
  161.                                this);  
  162.               
  163.             // 设置心跳检测时间  
  164.             struct timeval timeout = {_heart_time, 0};  
  165.             event_add(_event, &timeout);  
  166.               
  167.             _pTCPClientSignal->SignalEvent(_fd, ENE_CONNECTED);  
  168.               
  169.         } else if (events & (BEV_EVENT_READING|BEV_EVENT_WRITING|BEV_EVENT_EOF|BEV_EVENT_TIMEOUT)) {  
  170.             _pTCPClientSignal->SignalEvent(_fd, ENE_CLOSE);  
  171.         } else {  
  172.             _pTCPClientSignal->SignalEvent(_fd, EVE_UNKNOWN);  
  173.         }  
  174.           
  175.     }  
  176.       
  177.     void ActiveTCPClient::PutRecvData(void* data, size_t len) {  
  178.           
  179.         if (_pTCPClientSignal) {  
  180.             _pTCPClientSignal->SignalRecvData(_fd, data, len);  
  181.         }  
  182.           
  183.     }  
  184. }  

NetSignal.h
[html]   view plain  copy
  1. //  
  2. //  NetSignal.h  
  3. //  Frame  
  4. //  
  5. //  Created by chenjianjun on 15/9/8.  
  6. //  Copyright (c) 2015年 jsbn. All rights reserved.  
  7. //  
  8.   
  9. #ifndef __NetSignal_H_  
  10. #define __NetSignal_H_  
  11.   
  12. #include "Sigslot.h"  
  13. #include "Common.h"  
  14.   
  15. namespace NAME_SPACE {  
  16.       
  17.     class TCPServerSignal {  
  18.           
  19.     public:  
  20.         TCPServerSignal() {}  
  21.         ~TCPServerSignal() {}  
  22.           
  23.         // 客户端连接触发器  
  24.         sigslot::signal2<SOCKET , struct sockaddr_in*> SignalAccept;  
  25.         // 监听失败触发器  
  26.         sigslot::signal2<SOCKET , EM_NET_EVENT> SignalAcceptError;  
  27.     };  
  28.       
  29.     class TCPClientSignal {  
  30.           
  31.     public:  
  32.         TCPClientSignal() {}  
  33.         ~TCPClientSignal() {}  
  34.           
  35.         // 数据接收连接器  
  36.         sigslot::signal3<SOCKET, void*, size_t> SignalRecvData;  
  37.         // 套接字事件处理器  
  38.         sigslot::signal2<SOCKET, EM_NET_EVENT> SignalEvent;  
  39.     };  
  40.       
  41. }  
  42.   
  43. #endif /* defined(__NetSignal_H_) */  
借鉴了google的一个开源项目里面的sigslot机制,这里就不贴出来了,最后上一个测试代码
[cpp]   view plain  copy
  1. #include <glog/logging.h>  
  2. #include <map>  
  3. #include "NetFrame.h"  
  4. #include "ServerWorker.h"  
  5. #include "PassiveTCPClient.h"  
  6. #include "ActiveTCPClient.h"  
  7. #include "NetSignal.h"  
  8. #include "RWLock.h"  
  9.   
  10. using namespace NAME_SPACE;  
  11.   
  12. // 测试服务器  
  13. class TestServer : public sigslot::has_slots<>, public TCPClientSignal, public TCPServerSignal {  
  14.       
  15. public:  
  16.     TestServer() {  
  17.         pthread_mutex_init(&_work_mutex, nullptr);  
  18.     }  
  19.     ~TestServer() {  
  20.         pthread_mutex_destroy(&_work_mutex);  
  21.     }  
  22.       
  23.     int Start() {  
  24.           
  25.         _pServerWorker = new ServerWorker("192.168.1.74",8088);  
  26.           
  27.         SignalAccept.connect(this, &TestServer::Accept);  
  28.         SignalAcceptError.connect(this, &TestServer::Event);  
  29.         SignalRecvData.connect(this, &TestServer::RecvData);  
  30.         SignalEvent.connect(this, &TestServer::Event);  
  31.           
  32.         if (!_pServerWorker->StartWork(this)) {  
  33.             LOG(ERROR)<<"服务器监听启动失败";  
  34.             return FUNC_FAILED;  
  35.         }  
  36.           
  37.         return FUNC_SUCCESS;  
  38.     }  
  39.       
  40.     void Stop() {  
  41.           
  42.         _pServerWorker->StopWork();  
  43.           
  44.         pthread_mutex_lock(&_work_mutex);  
  45.         std::map<SOCKET, PassiveTCPClient*>::iterator it = _map_clients.begin();  
  46.         while (it != _map_clients.end()) {  
  47.             it->second->StopWork();  
  48.             delete it->second;  
  49.             _map_clients.erase(it++);  
  50.         }  
  51.         pthread_mutex_unlock(&_work_mutex);  
  52.           
  53.     }  
  54.       
  55.     int SendData(SOCKET fd, void* data, size_t len) {  
  56.           
  57.         pthread_mutex_lock(&_work_mutex);  
  58.         std::map<SOCKET, PassiveTCPClient*>::iterator it = _map_clients.find(fd);  
  59.         if (it != _map_clients.end()) {  
  60.             it->second->SendData(data, len);  
  61.         }  
  62.         pthread_mutex_unlock(&_work_mutex);  
  63.           
  64.         return 0;  
  65.     }  
  66.       
  67. public:  
  68.     // 数据接收  
  69.     void RecvData(SOCKET fd, void* data, size_t len) {  
  70.         // 接收到数据就回显,正常的程序师丢到队列里面去,让其他线程来处理  
  71.         SendData(fd, data, len);  
  72.     }  
  73.   
  74.     // 套接字事件处理器  
  75.     void Event(SOCKET fd, EM_NET_EVENT msg) {  
  76.           
  77.         LOG(ERROR)<<"收到事件通知."<< msg;  
  78.           
  79.         pthread_mutex_lock(&_work_mutex);  
  80.         std::map<SOCKET, PassiveTCPClient*>::iterator it = _map_clients.find(fd);  
  81.         if (it != _map_clients.end()) {  
  82.             it->second->StopWork();  
  83.             delete it->second;  
  84.             _map_clients.erase(it);  
  85.         }  
  86.         pthread_mutex_unlock(&_work_mutex);  
  87.           
  88.     }  
  89.   
  90.     // 客户端连接触发器  
  91.     void Accept(SOCKET fd, struct sockaddr_in* sa) {  
  92.           
  93.         LOG(ERROR)<<"收到客户端连接.";  
  94.           
  95.         pthread_mutex_lock(&_work_mutex);  
  96.           
  97.         std::map<SOCKET, PassiveTCPClient*>::iterator it = _map_clients.find(fd);  
  98.         if (it != _map_clients.end()) {  
  99.             it->second->StartWork(this);  
  100.             delete it->second;  
  101.             _map_clients.erase(it);  
  102.         }  
  103.           
  104.         PassiveTCPClient* pPassiveTCPClient = new PassiveTCPClient(fd, sa, 15);  
  105.         if (!pPassiveTCPClient->StartWork(this)) {  
  106.             LOG(ERROR)<<"启动客户端失败";  
  107.         } else {  
  108.             _map_clients[fd] = pPassiveTCPClient;  
  109.         }  
  110.           
  111.         pthread_mutex_unlock(&_work_mutex);  
  112.     }  
  113.       
  114. private:  
  115.     ServerWorker* _pServerWorker;  
  116.       
  117.     pthread_mutex_t _work_mutex;  
  118.     std::map<SOCKET, PassiveTCPClient*> _map_clients;  
  119. };  
  120.   
  121.   
  122. // 测试客户端  
  123. class TestClient : public sigslot::has_slots<>, public TCPClientSignal, public Runnable {  
  124.       
  125. public:  
  126.     TestClient():_is_run_flg(false) {  
  127.     }  
  128.       
  129.     ~TestClient() {  
  130.     }  
  131.       
  132.     int Start() {  
  133.         _pActiveTCPClient = new ActiveTCPClient("192.168.1.5", 8088, 15);  
  134.         _pActiveTCPClient->SetTCPClientSignal(this);  
  135.   
  136.         SignalEvent.connect(this, &TestClient::Event);  
  137.         SignalRecvData.connect(this, &TestClient::RecvData);  
  138.           
  139.         _is_run_flg = true;  
  140.         if (!_connect_thread.Start(this)) {  
  141.             _is_run_flg = false;  
  142.             delete _pActiveTCPClient;  
  143.             return FUNC_FAILED;  
  144.         }  
  145.           
  146.         return FUNC_SUCCESS;  
  147.     }  
  148.       
  149.     void Stop() {  
  150.           
  151.         if (_pActiveTCPClient) {  
  152.               
  153.             _is_run_flg = false;  
  154.             _connect_thread.Stop();  
  155.               
  156.             SignalEvent.disconnect(this);  
  157.             SignalRecvData.disconnect(this);  
  158.               
  159.             _pActiveTCPClient->StopWork();  
  160.               
  161.             delete _pActiveTCPClient;  
  162.             _pActiveTCPClient = nullptr;  
  163.         }  
  164.     }  
  165.       
  166.     int SendData(void* data,size_t len) {  
  167.           
  168.         if (_pActiveTCPClient) {  
  169.             _pActiveTCPClient->SendData(data, len);  
  170.         }  
  171.         return FUNC_SUCCESS;  
  172.     }  
  173.       
  174.     // 数据接收  
  175.     void RecvData(SOCKET fd, void* data, size_t len) {  
  176.         // 接收到数据就回显,正常的程序师丢到队列里面去,让其他线程来处理  
  177.         SendData(data, len);  
  178.     }  
  179.       
  180.     // 套接字事件处理器  
  181.     void Event(SOCKET fd, EM_NET_EVENT msg) {  
  182.           
  183.         if (msg == ENE_CONNECTED) {  
  184.         } else {  
  185.             _pActiveTCPClient->StopWork();  
  186.         }  
  187.           
  188.     }  
  189.       
  190. protected:  
  191.     virtual void Run(void* arg) {  
  192.           
  193.         //TestClient* p = (TestClient*)arg;  
  194.           
  195.         while (_is_run_flg) {  
  196.               
  197.             if (!_pActiveTCPClient->IsConnect()) {  
  198.                 _pActiveTCPClient->StartWork();  
  199.             }  
  200.               
  201.             Thread::SleepMs(2000);  
  202.         }  
  203.     }  
  204.       
  205. private:  
  206.     ActiveTCPClient* _pActiveTCPClient;  
  207.     // 运行标志  
  208.     volatile bool _is_run_flg;  
  209.     // 连接检测线程  
  210.     Thread _connect_thread;  
  211.       
  212. };  
  213.   
  214. int main(int argc,char* argv[]) {  
  215.       
  216.     // 初期化网络  
  217.     if (NetFrame::Instance()->NetWorkInit() != FUNC_SUCCESS) {  
  218.         LOG(ERROR)<<"网络初期化失败....";  
  219.         return -1;  
  220.     }  
  221.       
  222. //    {  
  223. //        // 测试服务器  
  224. //        TestServer mTestServer;  
  225. //        mTestServer.Start();  
  226. //        sleep(200);// 模拟测试,休眠10分钟时间来测试整个网络库  
  227. //        mTestServer.Stop();  
  228. //    }  
  229.       
  230. //    {  
  231. //        // 测试客户端  
  232. //        TestClient mTestClient;  
  233. //        mTestClient.Start();  
  234. //        char buf[4] = "bye";  
  235. //        for (int i = 0; i < 200; ++i) {  
  236. //            memset(buf, 0x00, sizeof(buf));  
  237. //            sprintf(buf, "%03d", i);  
  238. //            sleep(1);  
  239. //            mTestClient.SendData(buf, 3);  
  240. //        }  
  241. //          
  242. //        mTestClient.Stop();  
  243. //    }  
  244.       
  245.     // 关闭网络  
  246.     NetFrame::Instance()->NetWorkExit();  
  247.       
  248.     return 0;  
  249. }  

测试代码被注释了,打开就可以测试.

这里把主要代码贴了出来,一些其他的代码可以看我的github项目:

https://github.com/chenjianjun571/cioforandroid.Git

https://github.com/chenjianjun571/cioforios.git


FROM: http://blog.csdn.net/cjj198561/article/details/48370933




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libevent是一个事件驱动的网络库,用于开发高效的网络应用程序。它支持多线程编程,但是在使用libevent多线程模式时需要注意一些问题。首先,libevent的信号事件是不支持多线程的,因为它使用了全局变量。这意味着在多线程环境下,注册信号事件可能会导致竞争条件和错误的结果。这一点可以在中的文章中找到更详细的解释。为了避免这个问题,可以考虑使用其他方式处理信号事件。 另外,在多线程模式下,主线程和工作线程之间可能存在并发操作事件的问题。当一个线程注册事件时,另一个线程可能同时在操作事件,比如删除或修改事件。libevent的源代码中没有提供同步保护机制,这可能导致严重的问题。因此,在多线程模式下使用libevent时,需要谨慎处理事件的操作,确保线程安全。这一点可以在中的文章中找到更详细的说明。 总结来说,libevent支持多线程编程,但需要注意信号事件不支持多线程,并且需要处理并发操作事件的问题。在使用libevent多线程模式时,建议仔细阅读相关文档和源代码,确保线程安全性。123 #### 引用[.reference_title] - *1* *2* [libevent多线程](https://blog.csdn.net/zhbt1234/article/details/53782589)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}} ] [.reference_item] - *3* [libevent学习笔记十三:让libevent支持多线程](https://blog.csdn.net/jyl_sh/article/details/105895355)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值