kvstroe--reactor

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(&current, NULL);  // 获取当前时间

		int time_used = TIME_SUB_MS(current, begin);  // 计算时间差
		memcpy(&begin, &current, 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);  // 处理写事件
			}
		}
	}
}
posted @ 2025-02-25 00:15  nakejimamiyuki  阅读(8)  评论(0)    收藏  举报