学习记录,epoll方法网络IO通信 服务器端 IO驱动型写法
文章目录
一、监听端口
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(8888);
if (-1 == bind(socket_fd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr))) {
perror("bind");
return -1;
}
listen(socket_fd, 10);
二、相关结构体类型和函数解析
1.epoll_create函数
extern int epoll_create (int __size) __THROW;
作用:在内核建立一个事件表用来存储监视的socket和事件,返回文件描述符。所以后面epoll_wait函数不用将所有监视的socket传入传出内核。
2.epoll_event结构体类型
typedef union epoll_data
{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event
{
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
} __EPOLL_PACKED;
uint32_t events: 事件类型
epoll_data_t data: 文件描述符或文件指针
3.epoll_ctl函数
对内核中的监视事件表进行添加、删除和修改操作的函数。
extern int epoll_ctl (int __epfd, int __op, int __fd,
struct epoll_event *__event) __THROW;
int __epfd: 进行修改的监视事件表
int __op: 要进行的操作,有添加、删除和修改,对应
添加: EPOLL_CTL_ADD
删除: EPOLL_CTL_DEL
修改: EPOLL_CTL_MOD
int __fd: 要添加、删除或者修改的socket
struct epoll_event *__event: 绑定的事件,删除操作设置为NULL
4.epoll_wait函数
监视事件表是否有就绪socket,返回已就绪socket数量,并修改__events数组存储就绪的epoll_event
extern int epoll_wait (int __epfd, struct epoll_event *__events,
int __maxevents, int __timeout);
int __epfd: 进行监视的事件表
struct epoll_event *__events: 内核中存储已就绪的epoll_event数组
int __maxevents: 监听的最大数量
int __timeout: 超时时间ms
三、建立事件表和用来返回就绪epoll_event的数组
//建立事件表
int epoll_fd = epoll_create(1);
//定义epoll_wait进行返回就绪epoll_event的数组
struct epoll_event events[1024] = {0};
四、将监听端口的socket添加到监听事件表
struct epoll_event levent;
levent.data.fd = socket_fd;
levent.events = EPOLLIN;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &levent);
五、while循环epoll_wait并处理事件
以下为while循环体中的内容
1.epoll_wait监听事件表
int n_ready = epoll_wait(epoll_fd, events, 1024, -1);
2.根据返回的就绪socket数量对events中的事件进行处理,如果是监听socket就添加连接,如果是其它socket的epollin事件就进行通信
for(int i = 0; i < n_ready; i++){
int fd = events[i].data.fd;
if(fd == socket_fd){
sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
int new_socket = accept(socket_fd, (sockaddr*)&client_addr, &len);
printf("accept new socket connect, index: %d\n", new_socket);
struct epoll_event temp;
temp.data.fd = new_socket;
temp.events = EPOLLIN;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_socket, &temp);
}
else if(events[i].events & EPOLLIN){
char message[64] = {0};
if(0 == recv(fd, message, 64, 0)){
printf("client index %d disconnect.\n", i);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
continue;
}
printf("received message from client index %d, context: %s\n", fd, message);
strcpy(message, "Hello");
send(fd, message, 64, 0);
}
}
六、完整代码
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <sys/select.h>
int main() {
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(8888);
if (-1 == bind(socket_fd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr))) {
perror("bind");
return -1;
}
listen(socket_fd, 10);
//建立事件表
int epoll_fd = epoll_create(1);
//定义epoll_wait进行返回就绪epoll_event的数组
struct epoll_event events[1024] = {0};
struct epoll_event levent;
levent.data.fd = socket_fd;
levent.events = EPOLLIN;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &levent);
while(1){
int n_ready = epoll_wait(epoll_fd, events, 1024, -1);
for(int i = 0; i < n_ready; i++){
int fd = events[i].data.fd;
if(fd == socket_fd){
sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
int new_socket = accept(socket_fd, (sockaddr*)&client_addr, &len);
printf("accept new socket connect, index: %d\n", new_socket);
struct epoll_event temp;
temp.data.fd = new_socket;
temp.events = EPOLLIN;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_socket, &temp);
}
else if(events[i].events & EPOLLIN){
char message[64] = {0};
if(0 == recv(fd, message, 64, 0)){
printf("client index %d disconnect.\n", i);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
continue;
}
printf("received message from client index %d, context: %s\n", fd, message);
strcpy(message, "Hello");
send(fd, message, 64, 0);
}
}
}
}