监听连接
代码
// test_buffer_event.cpp
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#ifdef _WIN32
#else
#include <signal.h>
#endif
// 回调函数
void ListenCallback(struct evconnlistener *evc, evutil_socket_t client_socket,
struct sockaddr *client_addr, int socklen, void *arg) {
char ip[16] = {0};
evutil_inet_ntop(AF_INET, &((sockaddr_in *)client_addr)->sin_addr, ip,
sizeof(ip));
std::cout << "accept new connection from " << ip << std::endl;
}
int main(int argc, char *argv[]) {
// 端口地址
int server_port = 8080;
if (argc > 1) {
// 从命令行传入指定的端口号
server_port = atoi(argv[1]);
}
#ifdef _WIN32
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
#else
// 使用断开连接socket,会发出此信号,造成程序退出,因此忽略此信号
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
return 1;
}
#endif
std::cout << "test event server!\n";
// 创建libevent的上下文,默认是创建base锁
event_base *base = event_base_new();
if (base) {
std::cout << "event_base_new success!" << std::endl;
}
// 绑定端口
sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(server_port);
/**
Allocate a new evconnlistener object to listen for incoming TCP connections
on a given address.
@param base The event base to associate the listener with.
@param cb A callback to be invoked when a new connection arrives. If the
callback is NULL, the listener will be treated as disabled until the
callback is set.
@param ptr A user-supplied pointer to give to the callback.
@param flags Any number of LEV_OPT_* flags
@param backlog Passed to the listen() call to determine the length of the
acceptable connection backlog. Set to -1 for a reasonable default.
@param addr The address to listen for connections on.
@param socklen The length of the address.
*/
// struct evconnlistener *evconnlistener_new_bind(
// struct event_base * base, evconnlistener_cb cb, void *ptr, unsigned flags,
// int backlog, const struct sockaddr *sa, int socklen);
auto evc = evconnlistener_new_bind(base,
ListenCallback, // 回调函数
base, // 传给回调函数的参数
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
10, // listen缓存大小
(sockaddr *)&sin, sizeof(sin));
// 事件循环
// 判断事件是否发生,分发事件到回调函数
event_base_dispatch(base);
evconnlistener_free(evc);
// 释放libevent的上下文
event_base_free(base);
return 0;
}
代码中使用的函数主要是evconnlistener_new_bind, 该函数简化了event的操作,实现了绑定监听添加回调
编译
test_event_server:test_buffer_event.cpp
g++ $^ -o $@ -levent
clean:
rm -f test_event_server
rm -f *.o
make test_event_server
运行查看监听
处理事件
代码
#include <bits/types/struct_timeval.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#ifdef _WIN32
#else
#include <signal.h>
#endif
void ReadCallback(struct bufferevent *bev, void *ctx) {
char buf[1024] = {0};
int len = bufferevent_read(bev, buf, sizeof(buf) - 1);
std::cout << "recv data: " << buf << std::endl;
// 插入buffer链表
bufferevent_write(bev, "OK", 3);
}
void WriteCallback(struct bufferevent *bev, void *ctx) {
std::cout << "write callback" << std::endl;
}
void EventCallback(struct bufferevent *bev, short what, void *ctx) {
std::cout << "event callback" << std::endl;
if (what & BEV_EVENT_TIMEOUT && what & BEV_EVENT_READING) {
// 读超时
std::cout << "read timeout" << std::endl;
// 读取缓冲区中的内容
// 清理空间,关闭监听
bufferevent_free(bev);
} else if (what & BEV_EVENT_TIMEOUT && what & BEV_EVENT_WRITING) {
// 写超时
std::cout << "write timeout" << std::endl;
// 缓冲回滚
// 清理空间,关闭监听
bufferevent_free(bev);
} else if (what & BEV_EVENT_ERROR) {
// 错误
std::cout << "error" << std::endl;
// 清理空间,关闭监听
bufferevent_free(bev);
} else if (what & BEV_EVENT_EOF) {
// 对端关闭
std::cout << "EOF" << std::endl;
// 考虑缓冲的处理
// 清理空间,关闭监听
bufferevent_free(bev);
}
}
// 回调函数
void ListenCallback(struct evconnlistener *evc, evutil_socket_t client_socket,
struct sockaddr *client_addr, int socklen, void *arg) {
char ip[16] = {0};
evutil_inet_ntop(AF_INET, &((sockaddr_in *)client_addr)->sin_addr, ip,
sizeof(ip));
std::cout << "accept new connection from " << ip << std::endl;
event_base *base = (event_base *)arg;
// 创建bufferevent对象(read和write)
// BEV_OPT_CLOSE_ON_FREE表示当bufferevent销毁时,自动关闭底层的socket
struct bufferevent *bev =
bufferevent_socket_new(base, client_socket, BEV_OPT_CLOSE_ON_FREE);
if (!bev) {
std::cerr << "bufferevent_socket_new failed!" << std::endl;
return;
}
// 添加监控事件, 设置内部权限参数
bufferevent_enable(bev, EV_READ | EV_WRITE);
// 设置超时时间 ,第一个为秒,第二个数据为微秒
timeval t1 = {10, 0};
// 超时需要设置上,防止死连接的问题出现
bufferevent_set_timeouts(bev, &t1, &t1);
// 设置回调函数
bufferevent_setcb(bev, ReadCallback, WriteCallback, EventCallback, base);
}
int main(int argc, char *argv[]) {
// 端口地址
int server_port = 8080;
if (argc > 1) {
// 从命令行传入指定的端口号
server_port = atoi(argv[1]);
}
#ifdef _WIN32
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
#else
// 使用断开连接socket,会发出此信号,造成程序退出,因此忽略此信号
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
return 1;
}
#endif
std::cout << "test event server!\n";
// 创建libevent的上下文,默认是创建base锁
event_base *base = event_base_new();
if (base) {
std::cout << "event_base_new success!" << std::endl;
}
// 绑定端口
sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(server_port);
/**
Allocate a new evconnlistener object to listen for incoming TCP connections
on a given address.
@param base The event base to associate the listener with.
@param cb A callback to be invoked when a new connection arrives. If the
callback is NULL, the listener will be treated as disabled until the
callback is set.
@param ptr A user-supplied pointer to give to the callback.
@param flags Any number of LEV_OPT_* flags
@param backlog Passed to the listen() call to determine the length of the
acceptable connection backlog. Set to -1 for a reasonable default.
@param addr The address to listen for connections on.
@param socklen The length of the address.
*/
// struct evconnlistener *evconnlistener_new_bind(
// struct event_base * base, evconnlistener_cb cb, void *ptr, unsigned
// flags, int backlog, const struct sockaddr *sa, int socklen);
auto evc = evconnlistener_new_bind(base,
ListenCallback, // 回调函数
base, // 传给回调函数的参数
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
10, // listen缓存大小
(sockaddr *)&sin, sizeof(sin));
// 事件循环
// 判断事件是否发生,分发事件到回调函数
event_base_dispatch(base);
evconnlistener_free(evc);
// 释放libevent的上下文
event_base_free(base);
return 0;
}
测试
客户端连接超时后会自动断开