reactor.c
#include <errno.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <poll.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include "server.h" // 包含服务器相关的头文件,可能定义了结构体和函数原型
// 定义常量和宏
#define CONNECTION_SIZE 1024 // 最大连接数
#define MAX_PORTS 20 // 最大监听端口数
#define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000) // 计算时间差(毫秒)
// 是否启用键值存储功能
#if ENABLE_KVSTORE
typedef int (*msg_handler)(char *msg, int length, char *response); // 定义消息处理函数指针类型
static msg_handler kvs_handler; // 全局消息处理函数指针
// 处理客户端请求的函数
int kvs_request(struct conn *c) {
c->wlength = kvs_handler(c->rbuffer, c->rlength, c->wbuffer); // 调用消息处理函数,生成响应
}
// 处理响应的函数(未实现)
int kvs_response(struct conn *c) {
// 空实现,可根据需要补充
}
#endif
// 回调函数声明
int accept_cb(int fd); // 接受新连接的回调
int recv_cb(int fd); // 接收数据的回调
int send_cb(int fd); // 发送数据的回调
// 全局变量
int epfd = 0; // epoll文件描述符
struct timeval begin; // 用于记录开始时间
struct conn conn_list[CONNECTION_SIZE] = {0}; // 连接列表,存储每个连接的状态
// 设置epoll事件
int set_event(int fd, int event, int flag) {
if (flag) { // 添加事件
struct epoll_event ev;
ev.events = event;
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev); // 添加到epoll监控
} else { // 修改事件
struct epoll_event ev;
ev.events = event;
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev); // 修改epoll监控
}
}
// 注册事件到epoll
int event_register(int fd, int event) {
if (fd < 0) return -1;
conn_list[fd].fd = fd; // 初始化连接状态
conn_list[fd].r_action.recv_callback = recv_cb; // 设置接收回调
conn_list[fd].send_callback = send_cb; // 设置发送回调
// 清空缓冲区
memset(conn_list[fd].rbuffer, 0, BUFFER_LENGTH);
conn_list[fd].rlength = 0;
memset(conn_list[fd].wbuffer, 0, BUFFER_LENGTH);
conn_list[fd].wlength = 0;
set_event(fd, event, 1); // 添加事件到epoll
}
// 接受新连接的回调
int accept_cb(int fd) {
struct sockaddr_in clientaddr; // 客户端地址
socklen_t len = sizeof(clientaddr);
int clientfd = accept(fd, (struct sockaddr*)&clientaddr, &len); // 接受新连接
if (clientfd < 0) {
printf("accept errno: %d --> %s\n", errno, strerror(errno)); // 打印错误信息
return -1;
}
event_register(clientfd, EPOLLIN); // 注册新连接的读事件
// 每1000个连接打印一次性能信息
if ((clientfd % 1000) == 0) {
struct timeval current;
gettimeofday(¤t, NULL); // 获取当前时间
int time_used = TIME_SUB_MS(current, begin); // 计算时间差
memcpy(&begin, ¤t, sizeof(struct timeval)); // 更新开始时间
//printf("accept finished: %d, time_used: %d\n", clientfd, time_used);
}
return 0;
}
// 接收数据的回调
int recv_cb(int fd) {
memset(conn_list[fd].rbuffer, 0, BUFFER_LENGTH); // 清空接收缓冲区
int count = recv(fd, conn_list[fd].rbuffer, BUFFER_LENGTH, 0); // 接收数据
if (count == 0) { // 客户端断开连接
//printf("client disconnect: %d\n", fd);
close(fd); // 关闭连接
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); // 从epoll中删除
return 0;
} else if (count < 0) { // 接收失败
printf("count: %d, errno: %d, %s\n", count, errno, strerror(errno));
close(fd);
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
return 0;
}
conn_list[fd].rlength = count; // 更新接收数据长度
//printf("RECV: %s\n", conn_list[fd].rbuffer);
// 根据启用的功能处理请求
#if ENABLE_KVSTORE
kvs_request(&conn_list[fd]); // 调用键值存储请求处理
#elif ENABLE_HTTP
http_request(&conn_list[fd]); // 调用HTTP请求处理
#elif ENABLE_WEBSOCKET
ws_request(&conn_list[fd]); // 调用WebSocket请求处理
#endif
set_event(fd, EPOLLOUT, 0); // 修改事件为可写
return count;
}
// 发送数据的回调
int send_cb(int fd) {
#if ENABLE_HTTP
http_response(&conn_list[fd]); // 调用HTTP响应处理
#elif ENABLE_WEBSOCKET
ws_response(&conn_list[fd]); // 调用WebSocket响应处理
#elif ENABLE_KVSTORE
kvs_response(&conn_list[fd]); // 调用键值存储响应处理
#endif
int count = 0;
// 发送数据逻辑
if (conn_list[fd].wlength != 0) {
count = send(fd, conn_list[fd].wbuffer, conn_list[fd].wlength, 0); // 发送数据
}
set_event(fd, EPOLLIN, 0); // 修改事件为可读
return count;
}
// 初始化服务器
int r_init_server(unsigned short port) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字
if (sockfd < 0) {
printf("socket creation failed: %s\n", strerror(errno));
return -1;
}
struct sockaddr_in servaddr; // 服务器地址结构
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定到所有网络接口
servaddr.sin_port = htons(port); // 设置端口号
if (-1 == bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr))) {
printf("bind failed: %s\n", strerror(errno));
close(sockfd);
return -1;
}
listen(sockfd, 10); // 开始监听
//printf("listen finished: %d\n", sockfd); // 打印监听套接字
return sockfd;
}
// 启动Reactor模型的服务器
int reactor_start(unsigned short port, msg_handler handler) {
kvs_handler = handler; // 设置消息处理函数
epfd = epoll_create(1); // 创建epoll实例
if (epfd < 0) {
printf("epoll create failed: %s\n", strerror(errno));
return -1;
}
int i = 0;
for (i = 0; i < MAX_PORTS; i++) {
int sockfd = r_init_server(port + i); // 初始化服务器,监听多个端口
conn_list[sockfd].fd = sockfd;
conn_list[sockfd].r_action.recv_callback = accept_cb; // 设置接受新连接的回调
set_event(sockfd, EPOLLIN, 1); // 添加监听事件
}
gettimeofday(&begin, NULL); // 记录开始时间
while (1) { // 主循环
struct epoll_event events[1024] = {0}; // 存储就绪事件
int nready = epoll_wait(epfd, events, 1024, -1); // 等待事件
for (int i = 0; i < nready; i++) { // 遍历就绪事件
int connfd = events[i].data.fd;
// 根据事件类型调用回调函数
if (events[i].events & EPOLLIN) {
conn_list[connfd].r_action.recv_callback(connfd); // 处理读事件
}
if (events[i].events & EPOLLOUT) {
conn_list[connfd].send_callback(connfd); // 处理写事件
}
}
}
}