libevent 封装

封装libevent 用于网络模块;具体用法是直接继承这个虚基类,实现回调函数即可!

头文件:

/*================================================================
*   Copyright (C) 2016 All rights reserved.
*
*   filename:net_server.h
*   author:Jiang Canjun
*   create date:2016-6-28
================================================================*/
#pragma once
#include "struct_base.h"
class net_server
{
public:
	virtual ~net_server();
	net_server();
	/***************************************************************
	*函数名:   get_type
	*返回值:	unsigned int
	*函数功能:  取得服务器类型
	*****************************************************************/
	virtual unsigned int get_type() = 0;
	/***************************************************************
	*函数名:   set_type
	*参数1:		unsigned int
	*返回值:	void
	*函数功能:  设置服务器类型
	*****************************************************************/
	virtual void set_type(unsigned int type) = 0;
	/***************************************************************
	*函数名:   set_id
	*返回值:
	*参数1:    id 服务器标识
	*函数功能:  设置服务器标识
	*****************************************************************/
	virtual void set_id(unsigned int id) = 0;
	/***************************************************************
	*函数名:   get_id
	*返回值:	unsigned int
	*函数功能:  取得服务器标识
	*****************************************************************/
	virtual unsigned int get_id() = 0;
	/***************************************************************
	*函数名:   get_sys_
	*返回值:	char
	*参数1:    msg
	*函数功能: 取得系统状态百分比
	*****************************************************************/
	virtual char get_sys_() = 0;
	/***************************************************************
	*函数名:   send_msg
	*返回值:	void
	*参数1:    msg
	*函数功能: 发送接口
	*****************************************************************/
	virtual bool send_msg(msg_buffer &msg) = 0;
	/***************************************************************
	*函数名:   do_connect
	*返回值:	int 链接成功的套接字
	*参数1:    port链接端口
	*参数2:    ip链接地址
	*参数3:    arg服务器类型标识 传入回调函数以便记录
	*函数功能: 链接给定的服务器
	*****************************************************************/
	virtual int do_connect(int port, const char* ip, void *arg);
	/***************************************************************
	*函数名:   start
	*返回值:	void
	*参数1:    port监听端口
	*参数2:    ip监听地址
	*函数功能: 开始事件循环
	*****************************************************************/
	virtual void start(int port, const char* ip = NULL);
	/***************************************************************
	*函数名:   stop
	*返回值:	void
	*函数功能: 停止事件循环
	*****************************************************************/
	virtual void stop();
	/***************************************************************
	*函数名:   get_port
	*返回值:	int
	*函数功能: 取得端口
	*****************************************************************/
	virtual int get_port();
	/***************************************************************
	*函数名:   get_ip
	*返回值:	string
	*函数功能: 取得ip
	*****************************************************************/
	virtual std::string get_ip();

public:
	/***************************************************************
	*函数名:   do_read
	*参数1:    fd 链接
	*参数2:    arg this指针
	*返回值:   true or false
	*函数功能: 读取回调函数
	*****************************************************************/
	static void do_read(int fd, short events, void *arg);
	/***************************************************************
	*函数名:   do_accept
	*参数1:    listener 监听套接字
	*参数2:    event 事件类型
	*参数3:    arg this指针
	*返回值:   true or false
	*函数功能: 接收链接调函数
	*****************************************************************/
	static void do_accept(evutil_socket_t listener, short events, void *arg);
	/***************************************************************
	*函数名:   signal_cb
	*参数1:    sig 链接
	*参数2:    events 事件类型
	*参数3:    arg this指针
	*返回值:   true or false
	*函数功能: 信号调函数
	*****************************************************************/
	static void signal_cb(evutil_socket_t sig, short events, void *arg);
	/***************************************************************
	*函数名:   init
	*返回值:  void
	*函数功能: 初始化网络库
	*****************************************************************/
	virtual void init();
	/***************************************************************
	*函数名:   read
	*参数1:    fd 触发读事件的链接
	*参数2:    arg 
	*返回值:   true or false
	*函数功能: 读事件回调的函数--(子类继承之后实现此接口 则会被调用)
	*****************************************************************/
	virtual bool read(int fd, void *arg) = 0;
	/***************************************************************
	*函数名:   accept
	*参数1:    fd 触链接读事件的链接
	*参数2:    arg
	*返回值:   true or false
	*函数功能: 被连接事件回调的函数--(子类继承之后实现此接口 则会被调用)
	*****************************************************************/
	virtual bool accept(int fd, void *arg) = 0;
	/***************************************************************
	*函数名:   connect
	*参数1:    fd 触链接读事件的链接
	*参数2:    arg
	*返回值:   true or false
	*函数功能: 主动连接事件回调的函数--(子类继承之后实现此接口 则会被调用)
	*****************************************************************/
	virtual bool connect(int fd, void *arg) = 0;
	/***************************************************************
	*函数名:   signal
	*参数1:    sig 触信号读事件的链接
	*参数2:    events 事件类型
	*参数3:    arg
	*返回值:   true or false
	*函数功能: 写事件回调的函数--(子类继承之后实现此接口 则会被调用)
	*****************************************************************/
	virtual bool signal(evutil_socket_t sig, short events, void *arg) = 0;
public:
	struct event_base* m_base;
	int  m_timeout;
	int  m_port;
	char m_ip[64];
	unsigned int m_srv_id;
	bool m_is_exit;
};

  实现文件:

#include "net_server.h"
#include <signal.h>
#include "struct_base.h"
#ifdef WIN32
#pragma warning(disable: 4996)
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
void net_server::init()
{
#ifdef WIN32
	WSADATA		wsaData;
	DWORD		Ret;
	if ((Ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
	{
		perror("WSAStartBug\n");
	}
	if (evthread_use_windows_threads() != 0)
	{
		perror("use_windows_threads");
		exit(0);
	}
#else
	if (evthread_use_pthreads() != 0)
	{
		perror("use_windows_threads");
		exit(0);
	}
#endif
	m_timeout = 0;
	m_port = 0;
	m_is_exit = false;
	m_base = event_base_new();
	if (!m_base)
	{
		exit(0);
	}
}
net_server::~net_server()
{
	event_base_free(m_base);
#ifdef WIN32
	WSACleanup();
#endif
}
net_server::net_server()
{
	/* 忽略终端 I/O信号,STOP信号 */
#ifndef WIN32
	::signal(SIGTTOU, SIG_IGN);
	::signal(SIGTTIN, SIG_IGN);
	::signal(SIGTSTP, SIG_IGN);
	::signal(SIGHUP, SIG_IGN);
	::signal(SIGPIPE, SIG_IGN);
	//signal(SIGQUIT, SIG_IGN);
	//signal(SIGCHLD, SIG_IGN);
#endif
	//evthread_enable_lock_debuging();
	init();
}
void net_server::do_read(int fd, short events, void *arg)
{
	net_server* pThis = (net_server*)arg;
	if (pThis)
	{
		pThis->read(fd, NULL);
	}
}
void net_server::signal_cb(evutil_socket_t sig, short events, void *arg)
{
	net_server* pThis = (net_server*)(arg);
	if (pThis)
	{
		pThis->signal(sig, events, NULL);
	}
}
void net_server::do_accept(evutil_socket_t listener, short event, void *arg)
{
	net_server* pThis = (net_server*)(arg);
	struct sockaddr_storage ss;
#ifdef WIN32
	int slen = sizeof(ss);
#else
	socklen_t slen = sizeof(ss);
#endif
	int fd = ::accept(listener, (struct sockaddr*)&ss, &slen);
	if (fd <= 0)
	{
		return;
	}
	else
	{
		struct  linger l;
		l.l_onoff = 1;
		l.l_linger = 2;
		setsockopt(fd, SOL_SOCKET, SO_LINGER, (const char *)&l, sizeof(l));//有数据就延迟关闭
		if (0 == evutil_make_socket_nonblocking(fd))
		{
			struct event *pEvRead = new struct event();
			if (pEvRead)
			{
				event_set(pEvRead, fd, EV_READ | EV_PERSIST, do_read, arg);
				event_base_set(pThis->m_base, pEvRead);
				event_add(pEvRead, NULL);
				if (pThis)
					pThis->accept(fd, pEvRead);//记录
			}
		}
		else perror("nonblocking\n");
	}
}
void net_server::stop()
{
	m_is_exit = true;
	raise(SIGTERM);
}
void net_server::start(int port, const char* ip)
{
	m_port = port;
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	if (ip == NULL)
	{
		sin.sin_addr.s_addr = 0;
	}
	else
	{
		strncpy(m_ip, ip, strlen(ip));
		sin.sin_addr.s_addr = inet_addr(ip);
	}
	sin.sin_port = htons(m_port);
	int listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	int optval = 1;
	if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (const char*)&optval, sizeof(optval)) == -1)
	{
		perror("set SO_REUSEADDR");
	}
	if (::bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0)
	{
		perror("bind");
		return;
	}
	if (listen(listener, SOMAXCONN) < 0)
	{
		perror("listen");
		return;
	}
	evutil_make_socket_nonblocking(listener);
	if (m_base)
	{
		if (0 != evthread_make_base_notifiable(m_base))
		{
			return;
		}
		struct event *evListen = new struct event();
		if (evListen)
		{
			event_set(evListen, listener, EV_READ | EV_PERSIST, do_accept, (void *)this);
			// 设置为base事件  
			event_base_set(m_base, evListen);
			// 添加事件  
			event_add(evListen, NULL);
		}
		//关闭程序信号
		struct event *signal_inti = new struct event();
		if (signal_inti)
		{
			event_assign(signal_inti, m_base, 44, EV_SIGNAL | EV_PERSIST, signal_cb, (void *)this);
			event_base_set(m_base, signal_inti);
			event_add(signal_inti, NULL);
		}
		event_base_dispatch(m_base);
		if (evListen)
		{
			delete evListen;
		}
		if (signal_inti)
		{
			delete signal_inti;
		}
	}
	else perror("event_new");
}
int net_server::get_port()
{
	return m_port;
}
std::string net_server::get_ip()
{
	return m_ip;
}
int net_server::do_connect(int port, const char* ip, void *arg)
{
	int sock = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in srvAddr;
	srvAddr.sin_family = AF_INET;
	srvAddr.sin_addr.s_addr = inet_addr(ip);
	srvAddr.sin_port = htons(port);
	int ret = ::connect(sock, (sockaddr*)&srvAddr, sizeof(struct sockaddr_in));
	if (0 == ret)
	{
		struct  linger l;
		l.l_onoff = 1;
		l.l_linger = 2;
		setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char *)&l, sizeof(l));//有数据就延迟关闭
		if (0 == evutil_make_socket_nonblocking(sock))
		{
			struct event *pEvRead = new struct event();
			if (pEvRead)
			{
				event_set(pEvRead, sock, EV_READ | EV_PERSIST, do_read, (void*)this);
				event_base_set(m_base, pEvRead);
				event_add(pEvRead, NULL);
				this->connect(sock, pEvRead);
			}
		}
		else perror("nonblocking\n");
	}
	else
	{
		sock = 0;
	}
	return sock;
}

 检测套接字状态:

char net_worker::fd_enable(int fd)
{
	/*CAutoRWLock lock(&m_lock);
	bool bRet = false;
	if (m_fd_ev.find(fd) != m_fd_ev.end())
		bRet = true;
	*/
	char bRet = -1;
	FD_SET(fd, &m_enable_array);
	if (select(fd + 1, NULL, &m_enable_array, NULL, &m_tv) == 1)//检测是否准备好
	{
		bRet = 0;
	}
	else//缓存区满了
	{
		CAutoRWLock lock(&m_lock);
		if (m_fd_ev.find(fd) != m_fd_ev.end())
			bRet = 1;
	}
	FD_ZERO(&m_enable_array);

	return bRet;
}

  发送:

				int iResult = 0;
				char fd_status = fd_enable(msg.m_fd);
				if (fd_status == 0)
				{
					//iResult = send(msg.m_fd, msg.m_buf, msg.m_use_len, 0);
					do
					{
						int send_size = send(msg.m_fd, msg.m_buf + iResult, msg.m_use_len - iResult, 0);
						if (send_size <= 0)
						{
							if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
							{
								send_size = 0;
								continue;
							}
							else
							{
								break;
							}
						}
						iResult += send_size;
					} while (iResult < msg.m_use_len);
					buffree(msg);
				}
				else if (fd_status == 1)
				{
					m_out_deque.push(msg);
				}
				else
				{
					buffree(msg);
				}

  

 

posted on 2016-12-21 16:42  jiangcanjun  阅读(171)  评论(0)    收藏  举报

导航