libEvent使用另外一条线程发送数据

网上一直没有找到在另外一条线程发送数据资料,不知道是不是我的想法不对,总之,自己写了一份server端的代码。直接上代码

server.h:

#pragma once

#include "event.h"
#include "event2/util.h"
#include "event2/listener.h"
#include "AX_Thread.h"
#include "AX_Mutex.h"
#include <queue>
#include <map>

#define SAFE_DELETE(x) if(x){delete x;x=NULL;}
#define SAFE_DELETE_A(x) if(x){delete[] x;x=NULL;}

typedef struct Send_Data
{
 bufferevent* event;
 int len;
 char* data;
}Send_Data;

typedef std::map<bufferevent*, int> EventSocketMap;
typedef std::map<int, bufferevent*> SocketEventMap;
typedef std::map<bufferevent*, bool> SocketEventReadyMap;
typedef std::queue<Send_Data> SendDataList;

class CServer
{
public:
 CServer(void);
 ~CServer(void);

 virtual int Listen(char* ip, int port);
 virtual int Close(void);
 virtual int Heartbeat();
 virtual int Send(int id, char *pBuf, unsigned int nBufLen);

 virtual int event_dispath_msg();

 int SetRecvTPBuffSize(int size);
 int SetSelectTimeout(long sec, long usec);

private:
 void init();
 void run();
 static void* TcpSendThread(void* param);
 static void listener_cb(evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sock, int socklen, void *arg);
 static void socket_read_cb(bufferevent *bev, void *arg);
 static void socket_write_cb(bufferevent *bev, void *arg);
 static void socket_event_cb(bufferevent *bev, short events, void *arg);
 
private:
 EventSocketMap _EventSocketMap;
 SocketEventMap _SocketEventMap;
 SocketEventReadyMap _SocketEventReadyMap;
 event_base* _base;
 evconnlistener* _listener;
 bool _bRun;
 AX_hthread_t _SendThread;
 AX_Mutex _mutex;
 SendDataList _data_list;
 int _tpRecvBuffSize;
 char* _buffer;
};


server.cpp:

#include "Server.h"
#include "event2/thread.h"

CServer::CServer(void)
{
 _base = NULL;
 _listener = NULL;
 _bRun = false;
 _buffer = NULL;
 _tpRecvBuffSize = 0;
 init();
}

CServer::~CServer(void)
{

}

void CServer::init()
{
 WSAData wsa;
 if (::WSAStartup(MAKEWORD(2,2),&wsa) != 0)
  return;

 _EventSocketMap.clear();
 _SocketEventMap.clear();
 //使libEvent支持多线程
 evthread_use_windows_threads();
}

//socket发送线程
void CServer::run()
{
 while(_bRun)
 {
  _mutex.acquire();
  if(_data_list.size() <= 0)
  {
   _mutex.release();
   Sleep(50);
   continue;
  }

  Send_Data data = _data_list.front();
  _data_list.pop();
  _mutex.release();
  EventSocketMap::iterator it = _EventSocketMap.find(data.event);
  if(it == _EventSocketMap.end())
  {
   SAFE_DELETE_A(data.data);
   continue;
  }

  _mutex.acquire();
  if(!_SocketEventReadyMap[data.event])
  {
   //如果socket还没有准备好,将数据放到队列的最后
   _data_list.push(data);
   _mutex.release();
   printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\\n\n\n\n\
       ********************************************************************\
       socket not ready, event = %p\
       ********************************************************************\
       \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", data.event);
   continue;
  }

  _SocketEventReadyMap[data.event] = false;
  _mutex.release();
  int nResult = bufferevent_write(it->first, data.data, data.len);
  SAFE_DELETE_A(data.data);
 }
}

void* CServer::TcpSendThread(void* param)
{
 CServer* server = (CServer*)param;
 if(NULL != server)
 {
  server->run();
 }

 return NULL;
}

//一个新客户端连接上服务器了   
//当此函数被调用时,libevent已经帮我们accept了这个客户端。该客户端的文件描述符为fd 
void CServer::listener_cb(evconnlistener* listener, evutil_socket_t fd, struct sockaddr* sock, int socklen, void* arg)   
{
 CServer* server = (CServer*)arg;
 if(NULL != server)
 {
  event_base* base = server->_base;
  //为这个客户端分配一个bufferevent   
  bufferevent* bev =  bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);   
  bufferevent_setcb(bev, socket_read_cb, socket_write_cb, socket_event_cb, arg);   
  bufferevent_enable(bev, EV_READ | EV_PERSIST);
  server->_EventSocketMap[bev] = fd;
  server->_SocketEventMap[fd] = bev;
  server->_SocketEventReadyMap[bev] = true;
 }
}

//客户端有数据送达的时候会回调这个函数
void CServer::socket_read_cb(bufferevent* bev, void* arg)   
{
 CServer* server = (CServer*)arg;
 if(NULL != server)
 {
  //从缓存中读取客户端发送来的数据,这个读取出来的数据末尾可能没有\0
  size_t len = bufferevent_read(bev, server->_buffer, server->_tpRecvBuffSize-1);
  server->_buffer[len] = 0;
  printf("%s\n", server->_buffer);

  EventSocketMap::iterator it = server->_EventSocketMap.find(bev);
  if(it == server->_EventSocketMap.end())
   return;

  //往队列中添加要回复给客户端的数据
  char* reply = new char[64+len];
  sprintf(reply, "I has read your data : %s", server->_buffer);
  len = strlen(reply);
  server->Send(it->second, reply, len);
 }
}

//给客户端发送的数据发好了,socket就绪
void CServer::socket_write_cb(bufferevent* bev, void *arg)
{
 CServer* server = (CServer*)arg;
 if(NULL != server)
 {
  server->_mutex.acquire();
  server->_SocketEventReadyMap[bev] = true;
  server->_mutex.release();
 }
}

//其他事件回调,比如客户端断开连接等
void CServer::socket_event_cb(bufferevent *bev, short events, void *arg)   
{
 CServer* server = (CServer*)arg;
 if(NULL != server)
 {
  if (events & BEV_EVENT_EOF)
  {
   EventSocketMap::iterator it = server->_EventSocketMap.find(bev);
   if(it != server->_EventSocketMap.end())
   {
    SocketEventMap::iterator itSocket = server->_SocketEventMap.find(it->second);
    if(itSocket != server->_SocketEventMap.end())
    {
     server->_SocketEventMap.erase(itSocket);
    }

    server->_EventSocketMap.erase(it);
   }

   bufferevent_free(bev);

  }
  else if (events & BEV_EVENT_ERROR)
  {
   EventSocketMap::iterator it = server->_EventSocketMap.find(bev);
   if(it != server->_EventSocketMap.end())
   {
    SocketEventMap::iterator itSocket = server->_SocketEventMap.find(it->second);
    if(itSocket != server->_SocketEventMap.end())
    {
     server->_SocketEventMap.erase(itSocket);
    }

    server->_EventSocketMap.erase(it);
   }

   bufferevent_free(bev);
  }
  else
  {
   printf("socket event callback, event = %d\n", events);
  }
 }  
}

int CServer::Listen(char* ip, int port)
{
 struct sockaddr_in sin;
 memset(&sin, 0, sizeof(struct sockaddr_in));   
 sin.sin_family = AF_INET;   
 sin.sin_port = htons(port);
 //sin.sin_addr.s_addr = inet_addr(ip);

 _base = event_base_new();
 //使libEvent支持多线程
 evthread_make_base_notifiable(_base);
 _listener = evconnlistener_new_bind(_base, listener_cb, this, LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, 10, (struct sockaddr*)&sin, sizeof(struct sockaddr_in));
 if(_listener != NULL)
 {
  //创建一条发送数据的线程
  _bRun = true;
  if (AX_Thread::spawn(TcpSendThread, this, 0, 0, &_SendThread, 0, 0, 0) != 0)
  {
   _bRun = false;
   event_base_free(_base);
   _base = NULL;
   return -1;
  }

  return 0;
 }

 return -1;
}

int CServer::Close(void)
{
 _bRun = false;
 WaitForSingleObject(_SendThread, -1);
 return 0;
}

int CServer::Heartbeat()
{
 return 0;
}

int CServer::Send(int id, char *pBuf, unsigned int nBufLen)
{
 bufferevent* bev = _SocketEventMap[id];
 Send_Data data = {};
 data.event = bev;
 data.len = nBufLen;
 data.data = pBuf;
 _mutex.acquire();
 _data_list.push(data);
 _mutex.release();
 return 0;
}

int CServer::event_dispath_msg()
{
 return event_base_dispatch(_base);
}

int CServer::SetRecvTPBuffSize(int size)
{
 _tpRecvBuffSize = size;
 SAFE_DELETE_A(_buffer);
 _buffer = new char[_tpRecvBuffSize];
 memset(_buffer, 0, _tpRecvBuffSize);
 return 0;
}


int CServer::SetSelectTimeout(long sec, long usec)
{
 return 0;
}


main.cpp:

#include "Server.h"

int main()   
{
 CServer server;
 server.SetRecvTPBuffSize(1024);
 server.Listen("10.10.18.38", 99887);
 server.event_dispath_msg();
 return 0;   
}      


测试代码开了100条线程同时给server发数据,代码如下:

#include "event.h"
#include "event2/bufferevent.h"
#include "event2/buffer.h"
#include "event2/util.h"
#include "event2/thread.h"

#include <Windows.h>

int tcp_connect_server(const char* server_ip, int port);  
void read_msg_cb(struct bufferevent* bev, void* arg); 
void event_cb(struct bufferevent *bev, short event, void *arg); 

#define THREAD_COUNT 100
DWORD __stdcall ThreadProc(void* arg)
{
 evthread_use_windows_threads();
 struct event_base *base = event_base_new();
 evthread_make_base_notifiable(base);
 struct bufferevent* bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); 

 struct sockaddr_in server_addr; 
 memset(&server_addr, 0, sizeof(server_addr) ); 
 server_addr.sin_family = AF_INET; 
 server_addr.sin_port = htons(99887); 
 server_addr.sin_addr.s_addr = inet_addr("10.10.18.38");

 int result = bufferevent_socket_connect(bev, (struct sockaddr *)&server_addr, 
  sizeof(server_addr)); 

 bufferevent_setcb(bev, read_msg_cb, NULL, event_cb, (void*)bev); 
 bufferevent_enable(bev, EV_READ | EV_PERSIST); 
 event_base_dispatch(base);
 return 0;
}

int main(int argc, char** argv) 
{
 WSAData wsa;
 if (::WSAStartup(MAKEWORD(2,2),&wsa) != 0)
  return 0;

 DWORD threads[THREAD_COUNT] = {};
 HANDLE handles[THREAD_COUNT] = {};
 for(int i = 0; i < THREAD_COUNT; ++i)
 {
  handles[i] = CreateThread(NULL, 0, ThreadProc, 0, 0, &threads[i]); 
 }

 for(int i = 0; i < THREAD_COUNT; ++i)
 {
  WaitForSingleObject(handles[i], -1);
 }

 return 0;
}

int i = 0;
void read_msg_cb(struct bufferevent* bev, void* arg) 

 char msg[1024]; 

 size_t len = bufferevent_read(bev, msg, sizeof(msg)); 
 msg[len] = '\0'; 

 printf("%s\n", msg);

 Sleep(1);
 char temp[128] = {};
 sprintf(temp, "hello server, my address = %p, i send %d count data to you", bev, i++);
 bufferevent_write(bev, temp, strlen(temp));


void event_cb(struct bufferevent *bev, short event, void *arg) 

 if (event & BEV_EVENT_EOF)
 {
  printf("connection closed\n");
  bufferevent_free(bev); 
 }
 else if (event & BEV_EVENT_ERROR)
 {
  printf("some other error\n");
  bufferevent_free(bev);
 }
 else if( event & BEV_EVENT_CONNECTED) 
 {
  char data[] = "hello server, i am client\n";
  bufferevent_write(bev, data, strlen(data));
  return ; 
 }
 else
 {
  printf("event_cb, event = %d\n", event);
 }
}




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值