当前位置: 代码迷 >> 综合 >> Unix/Linux 编程:网络编程之 epoll与Reactor
  详细解决方案

Unix/Linux 编程:网络编程之 epoll与Reactor

热度:26   发布时间:2024-01-20 02:01:24.0

在上一篇文章中实现了epoll的非阻塞IO的服务端程序

可是如果实际应用中需要注册大量事件,一个超长的if代码块会严重降低代码的可读性和管理

因此参考了 Reactor模型的实现改写了epoll服务器。讲所有的事件处理函数都写成回调函数的形式。这里注意几个参数传递时候的坑。

/* Server based on EPOLL */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/epoll.h>#define BUFFER_LENGTH   1024struct sockitem {int epollfd;int sockfd;int (*callback)(int fd, int events, void* arg);
};int recv_cb(int fd, int events, void* arg) {if (!(events & EPOLLIN) || arg == NULL)return -1;printf("trigger recv_cb\n");struct epoll_event* ev = (struct epoll_event*)arg;struct sockitem* si = (struct sockitem*)ev->data.ptr;int clientfd = si->sockfd;int epoll_fd = si->epollfd;char buffer[BUFFER_LENGTH] = { 0 };int ret = recv(clientfd, buffer, BUFFER_LENGTH, 0);if (ret < 0) {if (errno == EAGAIN || errno == EWOULDBLOCK) {printf("read all data\n");}close(clientfd);ev->events = EPOLLIN | EPOLLET;ev->data.fd = clientfd;ev->data.ptr = NULL;free(si);epoll_ctl(epoll_fd, EPOLL_CTL_DEL, clientfd, ev);}else if (ret == 0) {printf(" disconnect clientfd:%d\n", clientfd);close(clientfd);ev->events = EPOLLIN | EPOLLET;ev->data.fd = clientfd;ev->data.ptr = NULL;free(si);epoll_ctl(epoll_fd, EPOLL_CTL_DEL, clientfd, ev);return 0;}else {printf("Recv: %s, %d Bytes\n", buffer, ret);if (send(clientfd, "Hello, you are connected!\n", 26, 0)== -1) {// send data error maybe some network issue.perror("send error");close(clientfd);}}
}// callback handler for accept events of the sockfd.
int accept_cb(int fd, int events, void* arg) {if (!(events & EPOLLIN) || arg == NULL)return -1;printf("trigger accept_cb\n");struct epoll_event* ev = (struct epoll_event*)arg;