libevent多线程信令处理

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;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值