网上一直没有找到在另外一条线程发送数据资料,不知道是不是我的想法不对,总之,自己写了一份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);
}
}