libevent库实现简易tcp服务器
流程分析
- 创建socket,设置端口复用,绑定四元组,开始监听。
- 初始化
event_base
结构体。
- 编写监听事件的回调函数和客户端读事件的回调函数。
- 初始化tcp监听事件,并加入
event_base
中。
- 开始
event
事件处理循环。
- 释放所有事件占用资源。
- 释放
event_base
占用资源。
服务端源码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <event2/event.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <unistd.h>
void conncb(evutil_socket_t fd, short events, void *arg);
void readcb(evutil_socket_t fd, short events, void *arg);
int main(int argc, char *argv[]) {
// 创建socket
int lfd = socket(AF_INET, SOCK_STREAM, 0);
// 设置端口复用
int opt = 1;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// 绑定
sockaddr_in serv;
memset(&serv, 0, sizeof(serv));
serv.sin_addr.s_addr = htonl(INADDR_ANY);
serv.sin_port = htons(8888);
serv.sin_family = AF_INET;
bind(lfd, (sockaddr*)&serv, sizeof(serv));
// 监听
listen(lfd, 1024);
// 创建event_base
event_base *base = event_base_new();
if (base == nullptr) {
perror("event_base_new()");
exit(-1);
}
// 创建监听文件描述符对应事件
event *ev = event_new(base, lfd, EV_READ|EV_PERSIST, conncb, base);
if (ev == nullptr) {
perror("event_new(lfd)");
exit(-1);
}
// 将新的事件添加到event_base
event_add(ev, nullptr);
// 进入事件循环
event_base_dispatch(base);
// 释放事件
event_base_free(base);
event_free(ev);
close(lfd);
return 0;
}
void conncb(evutil_socket_t fd, short events, void *arg) {
sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
int cfd = accept(fd, (sockaddr*)&addr, &addrlen);
if (cfd == -1) {
perror("accept");
exit(-1);
}
char ipstr[1024];
if (nullptr == inet_ntop(AF_INET, &addr.sin_addr.s_addr, ipstr, 1024)) {
perror("inet_ntop()");
exit(-1);
}
std::cout << "Accept from " << ipstr << ":" << ntohs(addr.sin_port) << " on " << cfd << std::endl;
// 创建客户端监听事件并放进event_base
event *connev = event_new((event_base*)arg, cfd, EV_READ|EV_PERSIST, readcb, connev);
if (connev == nullptr) {
perror("event_new(cfd)");
exit(-1);
}
event_add(connev, 0);
}
void readcb(evutil_socket_t fd, short events, void *arg) {
int n;
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
n = read(fd, buffer, sizeof(buffer));
if (n <= 0) {
close(fd);
// 将读事件从event_base移除
event_del((event*)arg);
}
std::cout << "Read from " << fd << ":" << buffer << std::endl;
write(fd, buffer, n);
}