IO多路复用---epoll的使用

本文深入解析epoll的工作原理与使用方法,通过一个简单的C语言示例程序,展示如何利用epoll进行高效的网络通信编程。包括epoll的创建、事件添加及等待事件处理等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录


前言

  • select:select(ionum,read,wirte,error,timeout) select拿着read、write、error的集合 timeout时间内询问有没有io准备好(可读可写)
  • poll:和select类似,但是把三个集合变为了一个集合
  • epoll:io准备好后,内核通知epoll,epoll将io就绪的节点加到epoll的就绪队列里,epoll_wait从就绪队列中取io就绪的节点。

提示:以下是本篇文章正文内容,下面案例可供参考

一、用法

#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//./epoll 8080
int main(int argc, char * argv[])
{
    if(argc < 2) return -1;
    int port = atoi(argv[1]);
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)  return -1;
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if(bind(sockfd, (struct sockaddr*)&addr,sizeof(struct sockaddr_in))) return -2;
    if(listen(sockfd, 5) < 0) return -3;
    int epfd = epoll_create(1);
    struct epoll_event ev;
    struct epoll_event events[1024];
    ev.events = EPOLLIN;
    ev.data.fd= sockfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD, sockfd, &ev);//加入红黑树
    while(1)
    {
        //epfd 根节点
        //events 袋子
        //1024 一次带回多少 不是最大的连接数 总数量的百分之一
        int nready = epoll_wait(epfd, events, 1024, -1);
        if(nready < -1) break;
        int i = 0;
        for(i=0; i<nready; i++)
        {
        	if(events[i].events.fd == scokfd){
				struct sockaddr_in client_addr;
                memset(&client_addr, 0, sizeof(struct sockaddr_in));
                socklen_t client_len = sizeof(client_addr);
                int client_fd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
                if(client_fd <= 0) continue;
                char str[INET_ADDRSTRLEN] = {0};
                printf("recv from %s at port %d\n", inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),ntohs(client_addr.sin_port));
                //边沿触发 有数据触发一次 可能读完 ET (适合小块) 
                //水平触发 有数据一直触发 直到读完 LT(默认 但是不可主动声明) listenfd 适合大块
                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = client_fd;
                epoll_ctl(epfd, EPOLL_CTL_ADD, client_fd, &ev);
			}else{
				if(events[i].events & EPOLLIN) {
                    int clientfd = events[i].data.fd;
                    char buffer[1024] = {0};
                    int ret = recv(clientfd, buffer, 1024, 0);
                    if(ret < 0){
                        //1 没数据返回-1 非阻塞
                        //2 不返回 阻塞
                        if(errno == EAGAIN || errno == EWOULDBLOCK) continue;
                        close(clientfd);
                        ev.events = EPOLLIN;
                        ev.data.fd = clientfd;
                        epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
                    }else if (ret == 0) {
                        //断开了 close wait 收到了final
                        printf("disconnect %d\n", clientfd);
                        close(clientfd);
                        ev.events = EPOLLIN;
                        ev.data.fd = clientfd;
                        epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
                    } else{
                        printf("Recv: %s, %d Bytes\n", buffer, ret);
                    } 
                }
                //可能会同时处理 可能上一次的没发送完
                if(events[i].events & EPOLLOUT) //send缓冲区满了 
                {
                    int clientfd = events[i].data.fd;
                    char buffer[1024] = {0};
                    send(clientfd,buffer,1024,0);
                }
			}
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值