https://blog.csdn.net/flyingleo1981/article/details/51862857
因为原作者是在linux平台下码的代码,所以我将其中不同的api提出来,简单的定义了下,只为以后编写代码调试用
/*multiserver.h */
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h>
#include <assert.h>
#include <event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
typedef HANDLE pthread_t;
class MultiServer;
class Conn;
class ConnQueue;
struct LibeventThread;
class Conn
{
friend class ConnQueue;
friend class MultiServer;
private:
const int mFd;
evbuffer *m_ReadBuf;
evbuffer *m_WriteBuf;
Conn *m_Prev;
Conn *m_Next;
LibeventThread *m_Thread;
Conn(int fd = 0):mFd(fd){ m_Prev = nullptr; m_Next = nullptr; }
~Conn(){};
public:
LibeventThread *GetThread(){ return m_Thread; }
int GetFd(){ return mFd; }
int GetReadBufferLen()
{
return evbuffer_get_length(m_ReadBuf);
}
int GetReadBuffer(char *buffer, int len)
{
return evbuffer_remove(m_ReadBuf, buffer, len);
}
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);
};
struct LibeventThread
{
pthread_t tid;
struct event_base *base;
struct event notifyEvent;
int notifyRecvFd;
int notifySendFd;
ConnQueue connectQueue;
MultiServer *tcpConnect;
};
class MultiServer
{
private:
static const int EXIT_CODE = -1;
static const int MAX_SIGNAL = 256;
private:
int m_ThreadCount;
int m_Port;
LibeventThread *m_MainBase;
LibeventThread *m_Threads;
event *m_signalEvents[MAX_SIGNAL];
private:
void SetupThread(LibeventThread *th);
static void *WorkerLibevent(void *arg);
static void ThreadProcess(int fd, short which, void *arg);
static void ListenerEventCb(evconnlistener *listener,
evutil_socket_t fd,sockaddr *sa,int socklen,void *userdata);
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){}
public:
MultiServer(int count);
~MultiServer();
void SetPort(int port){ m_Port = port; }
bool StartRun();
void StopRun(timeval *tv);
bool AddSignalEvent(int sig, void(*ptr)(int, short, void *));
bool DeleteSignalEvent(int sig);
event *AddTimerEvent(void(*PTR)(int, short, void *), timeval tv, bool once);
bool DeleteTimerEvent(event *ev);
};
#include "multiserver.h"
ConnQueue::ConnQueue()
{
m_head = new Conn(0);
m_tail = new Conn(0);
m_head->m_Prev = m_tail->m_Next = nullptr;
m_head->m_Next = m_tail;
m_tail->m_Prev = m_head;
}
ConnQueue::~ConnQueue()
{
Conn *tcur, *tnext;
tcur = m_head;
while (tcur != nullptr)
{
tnext = tcur->m_Next;
delete tcur;
tcur = tnext;
}
}
Conn * ConnQueue::InsertConn(int fd, LibeventThread *t)
{
Conn *c = new Conn(fd);
c->m_Thread = t;
Conn *next = m_head->m_Next;
c->m_Prev = m_head;
c->m_Next = m_head->m_Next;
m_head->m_Next = c;
next->m_Prev = c;
return c;
}
void ConnQueue::DeleteConn(Conn *c)
{
c->m_Prev->m_Next = c->m_Next;
c->m_Next->m_Prev = c->m_Prev;
delete c;
}
MultiServer::MultiServer(int count)
{
m_ThreadCount = count;
m_Port = -1;
m_MainBase = new LibeventThread;
m_Threads = new LibeventThread[m_ThreadCount];
m_MainBase->tid = GetCurrentThread();
m_MainBase->base = event_base_new();
memset(m_signalEvents, 0, sizeof(m_signalEvents));
for (int i = 0; i < m_ThreadCount;i++)
{
SetupThread(&m_Threads[i]);
}
}
MultiServer::~MultiServer()
{
StopRun(nullptr);
event_base_free(m_MainBase->base);
for (int i = 0; i < m_ThreadCount;i++)
{
event_base_free(m_Threads[i].base);
}
delete m_MainBase;
delete[] m_Threads;
}
#define pthread_create(a,b,c,d) CreateThread(nullptr,0,c,d,0,nullptr)
bool MultiServer::StartRun()
{
evconnlistener *listener=nullptr;
if (m_Port != EXIT_CODE)
{
sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(m_Port);
listener = evconnlistener_new_bind(m_MainBase->base,
ListenerEventCb, (void *)this,
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1,
(sockaddr *)&sin, sizeof(sockaddr_in));
if (nullptr == listener)
{
exit(0);
}
}
for (int i = 0; i < m_ThreadCount;i++)
{
pthread_create(&m_Threads[i].tid, nullptr,
(LPTHREAD_START_ROUTINE)WorkerLibevent, (void *)&m_Threads[i]);
}
event_base_dispatch(m_MainBase->base);
if (m_Port != EXIT_CODE)
{
evconnlistener_free(listener);
}
}
void MultiServer::StopRun(timeval *tv)
{
int contant = EXIT_CODE;
for (int i = 0; i < m_ThreadCount;i++)
{
send(m_Threads[i].notifySendFd, (char *)&contant, sizeof(int),0);
}
event_base_loopexit(m_MainBase->base, tv);
}
bool MultiServer::AddSignalEvent(int sig, void(*ptr)(int, short, void *))
{
if (sig >= MAX_SIGNAL)
{
return false;
}
event *ev = evsignal_new(m_MainBase->base, sig, ptr, this);
if (!ev || event_add(ev,nullptr) < 0)
{
event_del(ev);
return false;
}
if (nullptr != m_signalEvents[sig])
{
DeleteSignalEvent(sig);
}
m_signalEvents[sig] = ev;
return true;
}
bool MultiServer::DeleteSignalEvent(int sig)
{
event *ev = m_signalEvents[sig];
if (sig >= MAX_SIGNAL || nullptr == ev)
{
return false;
}
event_del(ev);
ev = nullptr;
return true;
}
#define pipe(int ) CreatePipe(nullptr,nullptr,nullptr,2)
void MultiServer::SetupThread(LibeventThread *th)
{
int res;
th->tcpConnect = this;
th->base = event_base_new();
assert(th->base != nullptr);
int fds[2];
res = pipe(fds);
assert(res == 0);
th->notifyRecvFd = fds[0];
th->notifySendFd = fds[1];
event_set(&th->notifyEvent, th->notifyRecvFd, EV_READ | EV_PERSIST, ThreadProcess, th);
event_base_set(th->base, &th->notifyEvent);
res = event_add(&th->notifyEvent, 0);
assert(res == 0);
}
void * MultiServer::WorkerLibevent(void *arg)
{
LibeventThread *th = (LibeventThread *)arg;
event_base_dispatch(th->base);
return th;
}
void MultiServer::ThreadProcess(int fd, short which, void *arg)
{
LibeventThread *th = (LibeventThread *)arg;
int pipefd = th->notifyRecvFd;
evutil_socket_t confd;
recv(pipefd, (char *)&confd, sizeof(evutil_socket_t), 0);
if (EXIT_CODE == confd)
{
event_base_loopbreak(th->base);
return;
}
struct bufferevent *bev;
bev = bufferevent_socket_new(th->base, confd, BEV_OPT_CLOSE_ON_FREE);
if (!bev)
{
event_base_loopbreak(th->base);
return;
}
Conn *conn = th->connectQueue.InsertConn(confd, th);
bufferevent_setcb(bev, ReadEventCB, WriteEventCB, CloseEventCB, conn);
bufferevent_enable(bev, EV_WRITE);
bufferevent_enable(bev, EV_READ);
th->tcpConnect->ConnectionEvent(conn);
}
void MultiServer::ListenerEventCb(evconnlistener *listener, evutil_socket_t fd, sockaddr *sa, int socklen, void *userdata)
{
MultiServer *server = (MultiServer *)userdata;
int num = rand() % server->m_ThreadCount;
int sendfd = server->m_Threads[num].notifySendFd;
send(sendfd, (char *)&fd, sizeof(evutil_socket_t), 0);
}
void MultiServer::ReadEventCB(struct bufferevent *bev, void *data)
{
Conn *conn = (Conn *)data;
conn->m_ReadBuf = bufferevent_get_input(bev);
conn->m_WriteBuf = bufferevent_get_output(bev);
conn->m_Thread->tcpConnect->ReadEvent(conn);
}
void MultiServer::WriteEventCB(struct bufferevent *bev, void *data)
{
Conn *conn = (Conn *)data;
conn->m_ReadBuf = bufferevent_get_input(bev);
conn->m_WriteBuf = bufferevent_get_output(bev);
conn->m_Thread->tcpConnect->WriteEvent(conn);
}
void MultiServer::CloseEventCB(struct bufferevent *bev, short events, void *data)
{
Conn *conn = (Conn *)data;
conn->m_Thread->tcpConnect->CloseEvent(conn, events);
conn->GetThread()->connectQueue.DeleteConn(conn);
bufferevent_free(bev);
}
event *MultiServer::AddTimerEvent(void(*PTR)(int, short, void *), timeval tv, bool once)
{
int flag = 0;
if (!once)
{
flag = EV_PERSIST;
}
event *ev = new event;
event_assign(ev, m_MainBase->base, -1, flag, PTR, this);
if (event_add(ev,&tv)<0)
{
event_del(ev);
return nullptr;
}
return ev;
}
bool MultiServer::DeleteTimerEvent(event *ev)
{
int res = event_del(ev);
return 0 == res;
}
#include "multiserver.h"
#include <set>
#include <vector>
#include <signal.h>
class TestServer : public MultiServer
{
private:
std::vector<Conn *> vec;
protected:
void ReadEvent(Conn *conn);
void WriteEvent(Conn *conn);
void ConnectionEvent(Conn *conn);
void CloseEvent(Conn *conn, short events);
public:
TestServer(int count) :MultiServer(count){}
~TestServer(){}
static void QuitCB(int sig, short event, void *data);
static void TimeoutCB(int fd, short events, void *data);
};
void TestServer::ReadEvent(Conn *conn)
{
conn->MoveBufferData();
}
void TestServer::WriteEvent(Conn *conn)
{
}
void TestServer::ConnectionEvent(Conn *conn)
{
TestServer *th = (TestServer *)conn->GetThread()->tcpConnect;
th->vec.push_back(conn);
}
void TestServer::CloseEvent(Conn *conn, short events)
{
}
void TestServer::QuitCB(int sig, short event, void *data)
{
TestServer *th = (TestServer *)data;
timeval tv = { 1, 0 };
th->StopRun(&tv);
}
void TestServer::TimeoutCB(int fd, short events, void *data)
{
TestServer *me = (TestServer *)data;
char temp[33] = "Hello world\n";
for (int i = 0; i < me->vec.size();i++)
{
me->vec[i]->AddtoWriteBuffer(temp, strlen(temp));
}
}
int main()
{
TestServer server(3);
server.AddSignalEvent(SIGINT, TestServer::QuitCB);
timeval tv = { 10, 0 };
server.AddTimerEvent(TestServer::TimeoutCB, tv, false);
server.SetPort(2111);
server.StartRun();
return 0;
}