epoll() 多路复用 和 两种工作模式

这篇具有很好参考价值的文章主要介绍了epoll() 多路复用 和 两种工作模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、epoll概述

epollLinux内核中的一个事件驱动I/O机制,用于处理多个文件描述符上的事件。它是一个高效且强大的I/O多路复用工具,可以用于处理大量文件描述符的I/O操作。epoll的主要优点是它只占用较少的资源,并且比传统的selectpoll更易于使用。

epoll的工作原理是通过一个事件表来跟踪所有需要监控的文件描述符。当某个文件描述符上有事件发生时,epoll会通知程序去处理这些事件。这种方式可以确保程序在等待某个文件描述符上有事件发生时只占用较少的资源,而不是像selectpoll那样整个程序都阻塞。

----来自CodeGeex

二、epoll

1.epoll API 介绍

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检测事件:
	- EPOLLIN
	- EPOLLOUT
	- EPOLLERR
	
// 对epoll实例进行管理:添加文件描述符信息,删除信息,修改信息
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
	- 参数:
		- epfd : epoll实例对应的文件描述符
		- op : 要进行什么操作
				EPOLL_CTL_ADD: 添加
				EPOLL_CTL_MOD: 修改
				EPOLL_CTL_DEL: 删除
		- fd : 要检测的文件描述符
		- event : 检测文件描述符什么事情

// 检测函数----检测epoll树中是否有就绪的文件描述符
// 创建了epfd,设置好某个fd上需要检测事件并将该fd绑定到epfd上去后,就可以调用epoll_wait
// 检测事件了
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
	- 参数:
		- epfd : epoll实例对应的文件描述符
		- events : 传出参数,保存了发送了变化的文件描述符的信息
		- maxevents : 第二个参数结构体数组的大小
		- timeout : 阻塞时间
			- 0 : 不阻塞
			- -1 : 阻塞,直到检测到fd数据发生变化,解除阻塞
			- > 0 : 阻塞的时长(毫秒)
	- 返回值:
		- 成功,返回发送变化的文件描述符的个数 > 0
		- 失败 -1

// 创建epoll实例,通过一棵红黑树管理待检测集合
// 参数 size 从 Linux 2.6.8 以后就不再使用,但是必须设置一个大于 0 的值。epoll_create 函数调用成功返回一个非负值的 epollfd,调用失败返回 -1。
int epoll_create(int size);
>>epoll_wait 缺点:
    ① epoll_wait 调用之后,需要将所有fd的event参数重新设置一遍,
      如果fd比较多的话,会比较消耗性能。----来自CodeGeeX

>>epoll_wait 优点:
    ① epoll_wait 调用之后,直接在event参数中拿到所有有事件就绪的fd,直接处理即可。
    ② 一般在fd数量比较多,但某段时间内,就绪事件fd数量较少的情况下,epoll_wait才会
    体现出它的优势,也就是说socket连接数量较大时而活跃连接较少时epoll模型更高效。

epoll() 多路复用 和 两种工作模式,epoll,多路复用,两种工作模式,ET模式,LT模式

// epoll 的使用
// 操作步骤
// 在服务器使用 epoll 进行 IO 多路转接的操作步骤如下:
    1.创建监听的套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);

    2.设置端口复用(可选)
    int opt = 1;
    setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    3.使用本地的IP与端口和监听的套接字进行绑定
    int ret = bind(lfd, (struct sockaddr*)&saddr, sizeof(saddr));

    4.给监听的套接字设置监听
    listen(lfd, 128);

    5.创建 epoll 实例
    int epfd = epoll_create(100);

    6.将用于监听的套接字添加到 epoll 实例中
    struct epoll_event ev;
    ev.events = EPOLLIN; //检测lfd读缓冲区是否有数据
    ev.data.fd = lfd;
    int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);

    接着创建一个数组,用于存储epoll_wait()返回的文件描述符
    struct epoll_event evs[1024];

    7.检测添加到epoll实例中的文件描述符是否已经就绪,并将这些已就绪的文件描述符进行处理
    int num = epoll_wait(epfd, evs, size, -1);

    ① 如果监听的是文件描述符,和新客户端建立连接,将得到的文件描述符添加到epoll实例中
    int cfd = accept(curfd,NULL,NULL);
    ev.events = EPOLLIN;
    ev.data.fd = cfd;

    新得到的文件描述符添加到epoll模型中,下一轮循环的时候就可以被检测了
    epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);

    ② 如果是通信的文件描述符,和对应的客户端通信,如果连接已断开,将该文件描述符从epoll实例中删除
    int len = recv(curfd,buf,sizeof(buf),0);
    if(len == 0) {
        // 将这个文件描述符从epoll实例中删除
        epoll_ctl(epfd, EPOLL_CTL_DEL, curfd, NULL);
        close(curfd);
    }else if(len > 0) {
        send(curfd,buf,len,0);
    }

    8.重复第 7 步的操作

往期文章推荐:

IO多路转接(复用)多线程 select 并发_呵呵哒( ̄▽ ̄)"的博客-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/132497986?spm=1001.2014.3001.5501

epoll() 多路复用 和 两种工作模式,epoll,多路复用,两种工作模式,ET模式,LT模式 

select/poll低效的原因之一是将“添加/维护待检测任务”和“阻塞进程/线程”两个步骤合二为一。每次调用select都需要这两步操作,然而大多数应用场景中,需要监视的socket个数相对固定,并不需要每次都修改。epoll将这两个操作分开,先用epoll_ctl()维护等待队列,再调用epoll_wait()阻塞进程(解耦)。通过下图的对比显而易见,epoll的效率得到了提升。


作者: 苏丙榅
链接: https://subingwen.cn/linux/epoll/
来源: 爱编程的大丙
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 第一种 IO多路转接技术:select/pollepoll() 多路复用 和 两种工作模式,epoll,多路复用,两种工作模式,ET模式,LT模式

 epoll() 多路复用 和 两种工作模式,epoll,多路复用,两种工作模式,ET模式,LT模式

epoll() 多路复用 和 两种工作模式,epoll,多路复用,两种工作模式,ET模式,LT模式

 

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

int main() {
    
    // 创建socket
    int lfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
    saddr.sin_addr.s_addr = INADDR_ANY;

    // 绑定
    int ret = bind(lfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(ret == -1) {
        perror("bind");
        exit(-1);
    }

    // 监听
    ret = listen(lfd,8);
    if(ret == -1) {
        perror("listen");
        exit(-1);
    }

    // 用epoll_create()创建一个epoll实例
    int epfd = epoll_create(100);
    
    // 将监听的文件描述符相关的检测信息添加到epoll实例中
    struct epoll_event epev;
    epev.events = EPOLLIN;
    epev.data.fd = lfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&epev);

    // 创建一个数组,用于存储epoll_wait()返回的文件描述符
    struct epoll_event epevs[1024];
    while (1) {
        ret = epoll_wait(epfd,epevs,1024,-1);
        if(ret == -1) {
            perror("epoll_wait");
            exit(-1);
        }
        printf("ret = %d\n",ret);
        for(int i = 0;i < ret;i++) {
            int curfd = epevs[i].data.fd;
            if(curfd == lfd) {
                // 监听的文件描述符有数据到达,有客户端连接
                struct sockaddr_in caddr;
                int len = sizeof(caddr);
                int cfd = accept(lfd,(struct sockaddr*)&caddr,&len);

                // epev.events = EPOLLIN | EPOLLOUT;
                epev.events = EPOLLIN;
                epev.data.fd = cfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&epev);

            } else {
                // if(epevs[i].events & EPOLLOUT) {
                //     continue;
                // }
                // 有数据到达,需要通信
                char buf[1024] = {0};
                int len = read(curfd,buf,sizeof(buf));
                if (len == -1) {
                    perror("read");
                    exit(-1);
                } else if(len == 0) {
                    printf("client closed...\n");
                    epoll_ctl(epfd,EPOLL_CTL_DEL,curfd,NULL);
                    close(curfd);
                } else if(len > 0) {
                    printf("recv buf = %s\n",buf);
                    write(curfd,buf,strlen(buf) + 1);
                }
            }
        }
    }
    close(lfd);
    close(epfd);
    return 0;
}

client.c

#include <stdio.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(int argc,char* argv[]) {
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd == -1) {
        perror("socket");
        return -1;
    }

    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
    inet_pton(AF_INET,"127.0.0.1",&saddr.sin_addr.s_addr);

    // 连接服务器
    int ret = connect(fd,(struct sockaddr*)&saddr,sizeof(saddr));

    if(ret == -1) {
        perror("connect");
        return -1;
    }

    int num = 0;
    while (1) {
        char sendBuf[1024] = {0};
        sprintf(sendBuf,"send data %d",num++);
        write(fd,sendBuf,strlen(sendBuf) + 1);

        // 接收
        int len = read(fd,sendBuf,sizeof(sendBuf));
        if(len == -1) {
            perror("read");
            return -1;
        }else if(len > 0) {
            printf("read buf = %s\n",sendBuf);
        }else{
            printf("服务器已经断开连接...\n");
            break;
        }
        // sleep(1);
        usleep(1000);
    }
    
    close(fd);
    return 0;
}

2.epoll 的两种工作模式 

Epoll 的工作模式:
	LT 模式 (水平触发)
		假设委托内核检测读事件 -> 检测fd的读缓冲区
			读缓冲区有数据 - > epoll检测到了会给用户通知
				a.用户不读数据,数据一直在缓冲区,epoll 会一直通知
				b.用户只读了一部分数据,epoll会通知
				c.缓冲区的数据读完了,不通知
	
	LT(level - triggered)是缺省的工作方式,并且同时支持 block 和 no-block socket。在这
	种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的 fd 进行 IO 操
	作。如果你不作任何操作,内核还是会继续通知你的。

	ET 模式(边沿触发)
		假设委托内核检测读事件 -> 检测fd的读缓冲区
			读缓冲区有数据 - > epoll检测到了会给用户通知
				a.用户不读数据,数据一直在缓冲区中,epoll下次检测的时候就不通知了
				b.用户只读了一部分数据,epoll不通知
				c.缓冲区的数据读完了,不通知

	ET(edge - triggered)是高速工作方式,只支持 no-block socket。在这种模式下,当描述
	符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,
	并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述
	符不再为就绪状态了。但是请注意,如果一直不对这个 fd 作 IO 操作(从而导致它再次变成
	未就绪),内核不会发送更多的通知(only once)。
	
	ET 模式在很大程度上减少了 epoll 事件被重复触发的次数,因此效率要比 LT 模式高。epoll
	工作在 ET 模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写
	操作把处理多个文件描述符的任务饿死。


综上所述:epoll的边沿模式下 epoll_wait检测到文件描述符有新事件才会通知,
如果不是新的事情就不通知,通知的次数比水平模式少,效率比水平模式高。

【注意】 ET模式需要配合循环+非阻塞

(1)LT 模式

epoll_lt.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

int main() {
    
    // 创建socket
    int lfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
    saddr.sin_addr.s_addr = INADDR_ANY;

    // 绑定
    int ret = bind(lfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(ret == -1) {
        perror("bind");
        exit(-1);
    }

    // 监听
    ret = listen(lfd,8);
    if(ret == -1) {
        perror("listen");
        exit(-1);
    }

    // 用epoll_create()创建一个epoll实例
    int epfd = epoll_create(100);
    
    // 将监听的文件描述符相关的检测信息添加到epoll实例中
    struct epoll_event epev;
    epev.events = EPOLLIN;
    epev.data.fd = lfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&epev);

    // 创建一个数组,用于存储epoll_wait()返回的文件描述符
    struct epoll_event epevs[1024];
    while (1) {
        ret = epoll_wait(epfd,epevs,1024,-1);
        if(ret == -1) {
            perror("epoll_wait");
            exit(-1);
        }
        printf("ret = %d\n",ret);
        for(int i = 0;i < ret;i++) {
            int curfd = epevs[i].data.fd;
            if(curfd == lfd) {
                // 监听的文件描述符有数据到达,有客户端连接
                struct sockaddr_in caddr;
                int len = sizeof(caddr);
                int cfd = accept(lfd,(struct sockaddr*)&caddr,&len);

                // epev.events = EPOLLIN | EPOLLOUT;
                epev.events = EPOLLIN;
                epev.data.fd = cfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&epev);

            } else {
                // if(epevs[i].events & EPOLLOUT) {
                //     continue;
                // }
                // 有数据到达,需要通信
                char buf[5] = {0};
                int len = read(curfd,buf,sizeof(buf));
                if (len == -1) {
                    perror("read");
                    exit(-1);
                } else if(len == 0) {
                    printf("client closed...\n");
                    epoll_ctl(epfd,EPOLL_CTL_DEL,curfd,NULL);
                    close(curfd);
                } else if(len > 0) {
                    printf("recv buf = %s\n",buf);
                    write(curfd,buf,strlen(buf) + 1);
                }
            }
        }
    }
    close(lfd);
    close(epfd);
    return 0;
}
(2)ET 模式
>> epoll在边沿模式下非阻塞接收数据
    循环接收数据的处理方式:对于每次接收的buffer多小都不重要了,只不过我们需要多接收几次数据。
    效率相对来说低一些;如果说buffer稍微大一点,接收数据的次数就少一些,效率相对来说高一些;
    可以把recv写到一个while循环里,通过while循环,每次读取5个字节,直到把客户端发过来的数据全部都读到本地。
    【思考】这种方式的弊端在哪里?
    【思考】进行套接字通信时阻塞的还是非阻塞的?

    【回答】很显然默认情况下进行套接字通信,这个处理流程是阻塞的。如果是阻塞的,
    当这个服务器端循环接收客户端发过来的数据,假设客户端发来了100个字节的数据,
    在服务端接收了20次,就把客户端发过来的数据全部读到本地了,但是在做第21次读
    数据的时候,这个recv它还能读到数据吗?
    没有了,也就是说这个文件描述符对应的读缓冲区里边是空的。如果说这个文件描述符
    对应的读缓冲区里边是空的。这个recv再去接收数据的话,服务器端的线程或者服务器
    端的进程它就阻塞了。如果这个线程/进程阻塞了,就不能干别的事情了。如果说写的
    这个程序里边就是单线程或者单进程的程序,在这里阻塞了,就不能够去做其他的事情
    了,整个程序就停止在这里了。

    【问题】如何让while循环中的break起作用?
        修改文件描述符为非阻塞,而不是修改read/recv函数,因为这函数时基于文件描述符
        去进行数据的接收操作,所以说需要修改一下这个文件描述符的属性,把这个文件描述
        符的默认阻塞属性修改为非阻塞属性。再次调用recv/read函数的时候,它们也就不会阻塞了

    【思考】如何把这个文件描述符修改为非阻塞属性?
        解决阻塞问题,需要将套接字默认的阻塞行为修改为非阻塞,需要使用fcntl()函数进行处理

        // 设置完成之后,读写都变成了非阻塞模式
        int flag = fcntl(cfd,F_GETFL);
        flag |= O_NOBLOCK;
        fcntl(cfd,F_SETFL,flag);  
>>什么时候使用EWOULDBLOCK?
    如果对于一个非阻塞socket,如果使用epoll边缘模式去检测数据是否可读,触发可读
    事件,一定要一次性把socket上的数据收取干净才行,也就是一定要循环调用recv函数
    直到recv出错,错误码是EWOULDBLOCK,这个错误码表示的就是没有数据可读了,
    这个时候才能退出循环,退出循环之后才能去处理可读事件。
    如果使用水平模式,则不用,你可以根据业务一次性收取固定的字节数,或者
    收完为止。
struct epoll_event {
    uint32_t events; /* Epoll events */
    epoll_data_t data; /* User data variable */
};

常见的Epoll检测事件:
    - EPOLLIN
    - EPOLLOUT
    - EPOLLERR
    - EPOLLET
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>

int main() {
    
    // 创建socket
    int lfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
    saddr.sin_addr.s_addr = INADDR_ANY;

    // 绑定
    int ret = bind(lfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(ret == -1) {
        perror("bind");
        exit(-1);
    }

    // 监听
    ret = listen(lfd,8);
    if(ret == -1) {
        perror("listen");
        exit(-1);
    }

    // 用epoll_create()创建一个epoll实例
    int epfd = epoll_create(100);
    
    // 将监听的文件描述符相关的检测信息添加到epoll实例中
    struct epoll_event epev;
    epev.events = EPOLLIN;
    epev.data.fd = lfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&epev);

    // 创建一个数组,用于存储epoll_wait()返回的文件描述符
    struct epoll_event epevs[1024];
    while (1) {
        ret = epoll_wait(epfd,epevs,1024,-1);
        if(ret == -1) {
            perror("epoll_wait");
            exit(-1);
        }
        printf("ret = %d\n",ret);
        for(int i = 0;i < ret;i++) {
            int curfd = epevs[i].data.fd;
            if(curfd == lfd) {
                // 监听的文件描述符有数据到达,有客户端连接
                struct sockaddr_in caddr;
                int len = sizeof(caddr);
                int cfd = accept(lfd,(struct sockaddr*)&caddr,&len);
                
                // 设置cfd属性非阻塞
                int flag = fcntl(cfd,F_GETFL);
                flag |= O_NONBLOCK; 
                fcntl(cfd,F_SETFL,flag);

                epev.events = EPOLLIN | EPOLLET;// 设置边沿触发
                epev.data.fd = cfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&epev);

            } else {
                if(epevs[i].events & EPOLLOUT) {
                    continue;
                }
                
                // 循环读取出所有的数据
                char buf[5];
                int len = 0;
                while ((len = read(curfd,buf,sizeof(buf))) > 0) {
                    // 打印数据
                    // printf("recv data : %s\n",buf);
                    write(STDOUT_FILENO,buf,len);
                    write(curfd,buf,len);
                }

                if(len == 0) {
                    printf("client closed...\n");
                }else if(len == -1) {
                    if(errno == EAGAIN) {
                        printf("data over......\n");
                    } else {
                        perror("read");
                        exit(-1);
                    }
                }
            }
        }
    }
    close(lfd);
    close(epfd);
    return 0;
}

client.c

#include <stdio.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(int argc,char* argv[]) {
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd == -1) {
        perror("socket");
        return -1;
    }

    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(9999);
    inet_pton(AF_INET,"127.0.0.1",&saddr.sin_addr.s_addr);

    // 连接服务器
    int ret = connect(fd,(struct sockaddr*)&saddr,sizeof(saddr));

    if(ret == -1) {
        perror("connect");
        return -1;
    }

    int num = 0;
    while (1) {
        char sendBuf[1024] = {0};
        // sprintf(sendBuf,"send data %d",num++);
        fgets(sendBuf,sizeof(sendBuf),stdin);
        write(fd,sendBuf,strlen(sendBuf) + 1);

        // 接收
        int len = read(fd,sendBuf,sizeof(sendBuf));
        if(len == -1) {
            perror("read");
            return -1;
        }else if(len > 0) {
            printf("read buf = %s\n",sendBuf);
        }else{
            printf("服务器已经断开连接...\n");
            break;
        }
        // sleep(1);
        // usleep(1000);
    }
    
    close(fd);
    return 0;
}

推荐和参考文章:

IO多路转接(复用)之epoll | 爱编程的大丙 (subingwen.cn)https://subingwen.cn/linux/epoll/

网络通信基础重难点解析 12 :Linux epoll 模型-腾讯云开发者社区-腾讯云 (tencent.com)https://cloud.tencent.com/developer/article/1419519

IO多路复用之select、poll、epoll之间的区别总结_io多路复用select,poll,epoll的区别_linux大本营的博客-CSDN博客https://blog.csdn.net/qq_40989769/article/details/128647476文章来源地址https://www.toymoban.com/news/detail-675685.html

到了这里,关于epoll() 多路复用 和 两种工作模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • epoll多路复用_并发服务器

    应用程序: 驱动程序:

    2024年02月15日
    浏览(51)
  • 驱动开发,IO多路复用实现过程,epoll方式

    被称为当前时代最好用的io多路复用方式; 核心操作:一棵树(红黑树)、一张表(内核链表)以及三个接口;  思想:(fd代表文件描述符)         epoll要把检测的事件fd挂载到内核空间红黑树上,遍历红黑树,调用每个fd对应的操作方法,找到发生事件的fd,如果没有发

    2024年02月07日
    浏览(51)
  • IO多路复用之select/poll/epoll

    掌握select编程模型,能够实现select版本的TCP服务器. 掌握poll编程模型,能够实现poll版本的TCP服务器. 掌握epoll的编程模型,能够实现epoll版本的TCP服务器. epoll的LT模式和ET模式. 理解select和epoll的优缺点对比. 提示:以下是本篇文章正文内容,下面案例可供参考 多路转接天然的是让我

    2023年04月09日
    浏览(73)
  • 深入理解网络 I/O 多路复用:Epoll

    🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者 📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代 🌲文章所在专栏:网络 I/O 🤔 我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识 💬 向我询问任何您想

    2024年02月05日
    浏览(43)
  • 网络编程 IO多路复用 [epoll版] (TCP网络聊天室)

    //head.h            头文件 //TcpGrpSer.c     服务器端 //TcpGrpUsr.c     客户端 通过IO多路复用实现服务器在单进程单线程下可以与多个客户端交互  API epoll函数  head.h TcpGrpSer.c TcpGrpUsr.c  

    2024年02月11日
    浏览(55)
  • Linux多路IO复用技术——epoll详解与一对多服务器实现

    本文详细介绍了Linux中epoll模型的优化原理和使用方法,以及如何利用epoll模型实现简易的一对多服务器。通过对epoll模型的优化和相关接口的解释,帮助读者理解epoll模型的工作原理和优缺点,同时附带代码实现和图解说明。

    2024年02月05日
    浏览(41)
  • 02-Linux-IO多路复用之select、poll和epoll详解

    前言: 在linux系统中,实际上所有的 I/O 设备都被抽象为了文件这个概念,一切皆文件,磁盘、网络数据、终端,甚至进程间通信工具管道 pipe 等都被当做文件对待。 在了解多路复用 select、poll、epoll 实现之前,我们先简单回忆复习以下两个概念: 一、什么是多路复用: 多路

    2024年02月10日
    浏览(54)
  • 【TCP服务器的演变过程】使用IO多路复用器epoll实现TCP服务器

    手把手教你从0开始编写TCP服务器程序,体验开局一块砖,大厦全靠垒。 为了避免篇幅过长使读者感到乏味,对【TCP服务器的开发】进行分阶段实现,一步步进行优化升级。 本节,在上一章节的基础上,将IO多路复用机制select改为更高效的IO多路复用机制epoll,使用epoll管理每

    2024年01月17日
    浏览(66)
  • 【高并发网络通信架构】引入IO多路复用(select,poll,epoll)实现高并发tcp服务端

    目录 一,往期文章 二,基本概念 IO多路复用 select 模型 poll 模型 epoll 模型 select,poll,epoll 三者对比 三,函数清单 1.select 方法 2.fd_set 结构体 3.poll 方法 4.struct pollfd 结构体 5.epoll_create 方法 6.epoll_ctl 方法 7.epoll_wait 方法 8.struct epoll_event 结构体 四,代码实现 select 操作流程 s

    2024年02月12日
    浏览(58)
  • 【高并发网络通信架构】3.引入IO多路复用(select,poll,epoll)实现高并发tcp服务端

    目录 一,往期文章 二,基本概念 IO多路复用 select 模型 poll 模型 epoll 模型 select,poll,epoll 三者对比 三,函数清单 1.select 方法 2.fd_set 结构体 3.poll 方法 4.struct pollfd 结构体 5.epoll_create 方法 6.epoll_ctl 方法 7.epoll_wait 方法 8.struct epoll_event 结构体 四,代码实现 select 操作流程 s

    2024年02月14日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包