基于epoll实现reactormox
流程:
- 创建socket文件描述符sockfd
- setsockopt设置端口复用
- bind绑定地址
- listen监听端口
- 创建epoll树epoll_create(1)
- 将sockfd上epoll树,同时通过epoll_event.data.ptr绑定监听处理函数等信息
- 内核监听
代码:
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/epoll.h>
#include<errno.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<ctype.h>
#define BUFFER_LENGTH 1024
struct sockitem {
int fd;
int (*callback)(int fd, int events, void* arg);
char recvbuffer[BUFFER_LENGTH];
char sendbuffer[BUFFER_LENGTH];
int rlength;
int slength;
};
struct reactor {
int epfd;
struct epoll_event events[1024];
};
reactor* eventloop = NULL;
int recv_cb(int fd, int events, void* arg);
int send_cb(int fd, int events, void* arg) {
struct sockitem* si = (struct sockitem*)arg;
struct epoll_event env;
send(fd, si->sendbuffer, si->slength, 0);
si->callback = recv_cb;
env.events = EPOLLIN | EPOLLET;
env.data.fd = fd;
env.data.ptr = si;
epoll_ctl(eventloop->epfd, EPOLL_CTL_MOD, fd, &env);
}
int recv_cb(int fd, int events, void* arg) {
struct sockitem* si = (struct sockitem*)arg;
struct epoll_event env;
memset(si->recvbuffer,0,BUFFER_LENGTH);
memset(si->sendbuffer, 0, BUFFER_LENGTH);
int ret = recv(fd, si->recvbuffer, BUFFER_LENGTH, 0);
if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return -1;
}
env.events = EPOLLIN;
epoll_ctl(eventloop->epfd, EPOLL_CTL_DEL, fd, &env);
close(fd);
free(si);
}
else if (ret == 0) {
printf("disconnect %d\n", fd);
env.events = EPOLLIN;
epoll_ctl(eventloop->epfd, EPOLL_CTL_DEL, fd, &env);
close(fd);
free(si);
}
else
{
printf("Recv: %s %d Bytes\n", si->recvbuffer, ret);
si->rlength = ret;
memcpy(si->sendbuffer, si->recvbuffer, si->rlength);
for (int i = 0; i < si->rlength; i++) {
si->sendbuffer[i] = toupper(si->sendbuffer[i]);
}
si->slength = si->rlength;
env.data.fd = fd;
env.events = EPOLLOUT | EPOLLET;
si->callback = send_cb;
env.data.ptr = si;
epoll_ctl(eventloop->epfd, EPOLL_CTL_MOD, fd, &env);
}
return 0;
}
int accept_cb(int fd, int events, void* arg) {
sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(sockaddr_in));
socklen_t len = sizeof(sockaddr_in);
int clientfd = accept(fd, (struct sockaddr*)&client_addr, &len);
if (clientfd < 0) {
perror("connect create fail!");
return 0;
}
printf("A new connect is estistabled,ip:%s port:%d\n", inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));
struct epoll_event env;
env.data.fd = clientfd;
env.events = EPOLLIN | EPOLLET;
struct sockitem* si = (struct sockitem*)malloc(sizeof(struct sockitem));
si->fd = clientfd;
si->callback = recv_cb;
env.data.ptr = si;
epoll_ctl(eventloop->epfd, EPOLL_CTL_ADD, clientfd, &env);
return clientfd;
}
int main() {
int sockfd,ret_log,opt=1,nready;
sockaddr_in serve_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket create fail!");
return 0;
}
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
memset(&serve_addr, 0, sizeof(sockaddr_in));
serve_addr.sin_family = AF_INET;
serve_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serve_addr.sin_port = htons(8888);
ret_log = bind(sockfd, (struct sockaddr*)&serve_addr, sizeof(sockaddr));
if (ret_log < 0) {
perror("bind fail!");
return 0;
}
ret_log = listen(sockfd, 1024);
if (ret_log < 0) {
perror("listen fail!");
return 0;
}
eventloop = (struct reactor*)malloc(sizeof(reactor));
eventloop->epfd = epoll_create(1);
struct epoll_event env;
env.events = EPOLLIN;
struct sockitem* si=(struct sockitem*)malloc(sizeof(sockitem));
si->fd = sockfd;
si->callback = accept_cb;
env.data.fd = sockfd;
env.data.ptr = si;
epoll_ctl(eventloop->epfd, EPOLL_CTL_ADD, sockfd, &env);
while (true)
{
nready = epoll_wait(eventloop->epfd, eventloop->events, 1024, -1);
if (nready <= 0) {
}
else {
for (int i = 0; i < nready; i++)
{
if (eventloop->events[i].events & EPOLLIN) {
struct sockitem* si = (struct sockitem*)eventloop->events[i].data.ptr;
si->callback(si->fd, eventloop->events[i].events, si);
}
if (eventloop->events[i].events & EPOLLOUT) {
struct sockitem* si = (struct sockitem*)eventloop->events[i].data.ptr;
si->callback(si->fd, eventloop->events[i].events, si);
}
}
}
}
close(eventloop->epfd);
close(sockfd);
return 0;
}