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) 收藏 举报
浙公网安备 33010602011771号