当前位置: 代码迷 >> 综合 >> linux中网络编程I/O模型---epoll
  详细解决方案

linux中网络编程I/O模型---epoll

热度:109   发布时间:2023-09-29 21:10:28.0

linux中网络编程I/O模型—epoll(异步I/O)

  1. epoll(异步I/O)模型使用,使用epoll模型需要用到一下3个函数:
    //创建一个epoll的句柄,size用来告诉系统内核要监听的文件描述符的数量
    //注:使用完epoll_create创建的句柄后需要close
    int epoll_create(int size);
    //epoll_ctl注册需要监听的事件类型。参数列表:
    epfd:epoll_create函数的返回值
    opt:可取值
描述
EPOLL_CTL_ADD 注册新的文件描述符到epfd中
EPOLL_CTL_MOD 修改已经注册的文件描述符事件
EPOLL_CTL_DEL 删除已经注册的文件描述符

events:参数结构如下

struct epoll_event{
    
__uint32_t events;    //epoll events
epoll_data_t data;     //user data avariable
}

其中events可取值如下:

描述
EPOLLIN 可读
EPOLLOUT 可写
EPOLLPRI 有紧急数据可读
EPOLLERR 文件描述符发生错误
EPOLLHUP 对应的文件描述符被挂断
EPOLLET 将EPOLL设为边缘触发模式,相对于水平触发模式而言
EPOLLONESHOT 只监听一次事件,当监听完成这次事件之后,如果还需要继续监听这个socket,需要吧这个socket添加到EPOLL、队列中

int epoll_ctl(int epfd, int opt, int fd, struct epoll_event *events);
//等待事件发生
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

  1. 使用epoll模型实现server、client
    server.cpp
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>#define IPADDRESS "127.0.0.1"
#define PORT 6666
#define MAXSIZE 1024
#define LISTENQ 5
#define FDSIZE 1000
#define EPOLLEVENTS 100//创建socket并绑定
int socket_bind(const char *ip, int port);
//IO 多路复用epoll
void do_epoll(int listenfd);
//事件处理
void handle_events(int epollfd, struct epoll_event *events, int num, int listenfd, char *buffer);
//处理新连接
void handle_accept(int epollfd, int listenfd);
//读处理
void do_read(int epollfd, int fd, char *buffer);
//写处理
void do_write(int epollfd, int fd, char *buffer);
//添加事件
void add_event(int epollfd, int fd, int state);
//修改事件
void modify_event(int epollfd, int fd, int state);
//删除事件
void delete_event(int epollfd, int fd, int state);int main()
{
    int listenfd;listenfd = socket_bind(IPADDRESS, PORT);listen(listenfd, LISTENQ);do_epoll(listenfd);return 0;
}int socket_bind(const char *ip, int port)
{
    int listenfd;if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
    perror("socket");exit(1);}struct sockaddr_in server;bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(port);inet_pton(AF_INET, ip, &server.sin_addr);if (bind(listenfd, (struct sockaddr*)&server, sizeof(struct sockaddr)) == -1){
    perror("bind");exit(2);}return listenfd;
}void do_epoll(int listenfd)
{
    int epollfd;struct epoll_event events[EPOLLEVENTS];int iret;char buffer[MAXSIZE];memset(buffer, 0, MAXSIZE);//创建监听描述符epollfd = epoll_create(FDSIZE);//添加监听描述符事件add_event(epollfd, listenfd, EPOLLIN);while (1){
    //获取已经准备好的描述符事件iret = epoll_wait(epollfd, events, EPOLLEVENTS, -1);handle_events(epollfd, events, iret, listenfd, buffer);}close(epollfd);
}void handle_events(int epollfd, epoll_event *events, int num, int listenfd, char *buffer)
{
    int i;int fd;//进行选好遍历for (i = 0; i < num; i++){
    fd = events[i].data.fd;//根据描述符的事件类型进行处理if (fd == listenfd && events[i].events & EPOLLIN){
    handle_accept(epollfd, listenfd);}else if (events[i].events & EPOLLIN){
    do_read(epollfd, fd, buffer);}else if (events[i].events & EPOLLOUT){
    do_write(epollfd, fd, buffer);}}
}void handle_accept(int epollfd, int listenfd)
{
    int clientfd;struct sockaddr_in client;socklen_t socklen;if ((clientfd = accept(listenfd, (struct sockaddr*)&client, &socklen)) == -1){
    perror("accept");}else{
    printf("accept a new client : %s : %d\n", inet_ntoa(client.sin_addr), client.sin_port);add_event(epollfd, clientfd, EPOLLIN);}
}void do_read(int epollfd, int fd, char *buffer)
{
    int nread;nread = read(fd, buffer, MAXSIZE);if (nread == -1){
    perror("read");close(fd);delete_event(epollfd, fd, EPOLLIN);}else if (nread == 0){
    fprintf(stderr, "client close.\n");close(fd);delete_event(epollfd, fd, EPOLLIN);}else{
    printf("read message is : %s\n", buffer);//将描述符的对应事件由读改成写modify_event(epollfd, fd, EPOLLOUT);}
}void do_write(int epollfd, int fd, char *buffer)
{
    int nwrite;nwrite = write(fd, buffer, strlen(buffer));if (nwrite == -1){
    perror("write error : ");close(fd);delete_event(epollfd, fd, EPOLLOUT);}else{
    modify_event(epollfd, fd, EPOLLIN);}memset(buffer, 0, MAXSIZE);
}void add_event(int epollfd, int fd, int state)
{
    struct epoll_event ev;ev.events = state;ev.data.fd = fd;epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
}void modify_event(int epollfd, int fd, int state)
{
    struct epoll_event ev;ev.events = state;ev.data.fd = fd;epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev);
}void delete_event(int epollfd, int fd, int state)
{
    struct epoll_event ev;ev.events = state;ev.data.fd = fd;epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev);
}

client.cpp

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAXSIZE 1024
#define IPADDRESS "127.0.0.1"
#define PORT 6666
#define FDSIZE 1024
#define EPOLLEVENTS 20void handle_connection(int sockfd);
void handle_event(int epollfd, struct epoll_event *events, int num, int sockfd, char *buffer);
void do_read(int epoolfd, int fd, int sockfd, char *buffer);
void do_write(int epollfd, int fd, int sockfd, char *buffer);
void add_event(int epollfd, int fd, int state);
void modify_event(int epollfd, int fd, int state);
void delete_event(int epollfd, int fd, int state);int count = 0;int main()
{
    int sockfd;sockfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in client;client.sin_family = AF_INET;client.sin_port = htons(PORT);inet_pton(AF_INET, IPADDRESS, &client.sin_addr);connect(sockfd, (struct sockaddr*)&client, sizeof(client));handle_connection(sockfd);close(sockfd);return 0;
}void handle_connection(int sockfd)
{
    int epollfd;struct epoll_event events[EPOLLEVENTS];char buffer[MAXSIZE];int iret;epollfd = epoll_create(FDSIZE);//add_event(epollfd, sockfd, EPOLLIN | EPOLLOUT);add_event(epollfd, STDIN_FILENO, EPOLLIN);while (1){
    iret = epoll_wait(epollfd, events, EPOLLEVENTS, -1);handle_event(epollfd, events, iret, sockfd, buffer);}close(epollfd);
}void handle_event(int epollfd, epoll_event *events, int num, int sockfd, char *buffer)
{
    int fd;int i;for (i = 0; i < num; i++){
    fd = events[i].data.fd;if (events[i].events & EPOLLIN)do_read(epollfd, fd, sockfd, buffer);else if (events[i].events & EPOLLOUT)do_write(epollfd, fd, sockfd, buffer);}
}void do_read(int epollfd, int fd, int sockfd, char *buffer)
{
    int nread;nread = read(fd, buffer, MAXSIZE);if (nread == -1){
    perror("read error");close(fd);}else if (nread == 0){
    fprintf(stderr, "server close.\n");close(fd);}else{
    if (fd == STDIN_FILENO)add_event(epollfd, sockfd, EPOLLOUT);else{
    delete_event(epollfd, sockfd, EPOLLIN);add_event(epollfd, STDOUT_FILENO, EPOLLOUT);}}
}void do_write(int epollfd, int fd, int sockfd, char *buffer)
{
    int nwrite;char temp[100];buffer[strlen(buffer) - 1] = '\0';snprintf(temp, sizeof(temp), "%s_%02d\n", buffer, count++);nwrite = write(fd, temp, strlen(temp));if (nwrite == -1){
    perror("write error");close(fd);}else{
    if (fd == STDOUT_FILENO)delete_event(epollfd, fd, EPOLLOUT);elsemodify_event(epollfd, fd, EPOLLIN);}memset(buffer, 0, MAXSIZE);
}void add_event(int epollfd, int fd, int state)
{
    struct epoll_event ev;ev.events = state;ev.data.fd = fd;epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
}void modify_event(int epollfd, int fd, int state)
{
    struct epoll_event ev;ev.events = state;ev.data.fd = fd;epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev);
}void delete_event(int epollfd, int fd, int state)
{
    struct epoll_event ev;ev.events = state;ev.data.fd = fd;epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev);
}