使用 libevent 开发服务器可以分为以下几个核心步骤:
1. 基本服务器结构
#include <event2/event.h> #include <event2/listener.h> #include <event2/bufferevent.h> #include <string.h> #include <stdlib.h> struct client_info { struct bufferevent *bev; // 可以添加其他客户端信息 }; // 读取回调函数 void read_cb(struct bufferevent *bev, void *ctx) { struct evbuffer *input = bufferevent_get_input(bev); struct evbuffer *output = bufferevent_get_output(bev); // 将输入数据直接回显(echo服务器) evbuffer_add_buffer(output, input); // 或者处理特定协议 size_t len = evbuffer_get_length(input); if (len > 0) { char *data = malloc(len + 1); evbuffer_remove(input, data, len); data[len] = '\0'; printf("Received: %s", data); // 处理业务逻辑 // ... free(data); } } // 事件回调函数 void event_cb(struct bufferevent *bev, short events, void *ctx) { if (events & BEV_EVENT_ERROR) { perror("Error from bufferevent"); } if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) { bufferevent_free(bev); } } // 接受新连接回调 void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *address, int socklen, void *ctx) { struct event_base *base = evconnlistener_get_base(listener); // 为每个新连接创建bufferevent struct bufferevent *bev = bufferevent_socket_new( base, fd, BEV_OPT_CLOSE_ON_FREE); // 设置回调函数 bufferevent_setcb(bev, read_cb, NULL, event_cb, NULL); bufferevent_enable(bev, EV_READ | EV_WRITE); printf("New client connected\n"); }
2. 完整的服务器示例
#include <event2/event.h> #include <event2/listener.h> #include <event2/bufferevent.h> #include <event2/buffer.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #define PORT 8888 void read_cb(struct bufferevent *bev, void *ctx) { struct evbuffer *input = bufferevent_get_input(bev); struct evbuffer *output = bufferevent_get_output(bev); size_t len = evbuffer_get_length(input); if (len > 0) { char *data = malloc(len + 1); evbuffer_remove(input, data, len); data[len] = '\0'; printf("Received %zu bytes: %s", len, data); // 简单的响应 char response[1024]; snprintf(response, sizeof(response), "Server received: %s", data); bufferevent_write(bev, response, strlen(response)); free(data); } } void event_cb(struct bufferevent *bev, short events, void *ctx) { if (events & BEV_EVENT_ERROR) { printf("Bufferevent error: %s\n", evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); } if (events & BEV_EVENT_EOF) { printf("Client disconnected\n"); } if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) { bufferevent_free(bev); } } void accept_error_cb(struct evconnlistener *listener, void *ctx) { struct event_base *base = evconnlistener_get_base(listener); int err = EVUTIL_SOCKET_ERROR(); fprintf(stderr, "Got an error %d (%s) on the listener. " "Shutting down.\n", err, evutil_socket_error_to_string(err)); event_base_loopexit(base, NULL); } int main() { struct event_base *base; struct evconnlistener *listener; struct sockaddr_in sin; // 创建event_base base = event_base_new(); if (!base) { fprintf(stderr, "Could not initialize libevent!\n"); return 1; } // 设置服务器地址 memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0); // 0.0.0.0 sin.sin_port = htons(PORT); // 创建监听器 listener = evconnlistener_new_bind( base, accept_conn_cb, NULL, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (struct sockaddr*)&sin, sizeof(sin)); if (!listener) { fprintf(stderr, "Could not create a listener!\n"); return 1; } evconnlistener_set_error_cb(listener, accept_error_cb); printf("Server started on port %d\n", PORT); // 进入事件循环 event_base_dispatch(base); // 清理资源 evconnlistener_free(listener); event_base_free(base); return 0; }
3. 编译命令
编译服务器 gcc -o server server.c -levent 如果使用OpenSSL gcc -o server server.c -levent -levent_openssl -lssl -lcrypto 调试版本 gcc -g -o server server.c -levent
4. 高级特性使用
#include <event2/event.h> void timer_cb(evutil_socket_t fd, short event, void *arg) { printf("Timer triggered\n"); } void add_timer(struct event_base *base) { struct timeval tv = {1, 0}; // 1秒 struct event *timer = event_new(base, -1, EV_PERSIST, timer_cb, NULL); event_add(timer, &tv); }
#include <event2/event.h> #include <signal.h> void signal_cb(evutil_socket_t fd, short event, void *arg) { struct event_base *base = arg; printf("Received signal %d, shutting down\n", fd); event_base_loopbreak(base); } void setup_signal_handler(struct event_base *base) { struct event *signal_event = evsignal_new(base, SIGINT, signal_cb, base); event_add(signal_event, NULL); }
5. 性能优化建议
1、使用线程池:对于CPU密集型任务
2、缓冲区管理:合理设置缓冲区大小
3、连接管理:实现连接超时和心跳机制
4、资源回收:及时释放不用的连接
6. 常见问题解决
内存泄漏:确保正确释放所有分配的资源
连接数限制:调整系统文件描述符限制
性能瓶颈:使用epoll
或kqueue
作为后端
这个框架可以帮助你快速开始使用 libevent 开发高性能的网络服务器,根据具体需求,你可以在此基础上添加协议解析、业务逻辑处理等功能。
文章摘自:https://idc.huochengrm.cn/fwq/17637.html
评论