我的网络观(2)——网络的IO多路复用机制

简介: 本文详解网络IO复用三大机制:SELECT(位图轮询,有FD数量限制)、POLL(事件分离,避免重复拷贝)与EPOLL(内核事件通知,高效无遍历)。对比一请求一线程模型的高开销,三者通过单线程管理多连接显著提升并发性能,是高性能服务器基石。

如何实现网络的IO复用

一请求一线程服务器的优劣

对于一请求一线程,其优势主要在于代码逻辑简单,但由于该方案对在连接与线程绑定,面对大并发的需求,会造成极大的线程切换开销和内存占用。故而我们需要设计更加适配并发的服务器方案

SELECT方案

他的设计思想是把所有关注的IO都放进一个fd_set类型的变量里,然后通过select函数将fd_set从用户态copy到内核态,根据就绪事件进行修改然后再传回,根据传回的结果,先判断是否要新建连接,再判断是否要读、写、异常处理。

select由一个结构体fd_set,一个函数select,四个集合操作宏FD_ZERO、FD_SET、FD_CLR、FD_ISSET组成

  • fd_set:用位图存储fd
  • FD_ZERO(&set):清空集合
  • FD_SET(fd, &set):添加集合
  • FD_CLR(fd, &set):删除集合
  • FD_ISSET(fd, &set):判断fd是否在集合中
  • select(int maxfd+1,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout):将位图从用户态送进内核态修改的系统调用

fd_set rfds,rset;
FD_ZERO(&rfds);
FD_SET(sockfd,&rfds);

    int maxfd = sockfd;
    INFO("maxfd:%d\n",maxfd);
    while(1){

        rset = rfds;
//获取就绪集合  
        int nready = select(maxfd+1, &rset,NULL,NULL,NULL);//集合上界,关注(读,写,异常),超时
        INFO("nready:%d\n",nready);
//当监听套接字在就绪集合内,创建连接
        if(FD_ISSET(sockfd,&rset)){
            int clientfd = accept(sockfd,(struct sockaddr*)&client_addr,&len);
            FD_SET(clientfd,&rfds);

            if(clientfd > maxfd)maxfd = clientfd;        
        }    
//遍历所有连接,按照就绪集合处理数据
        int i=0;
        for(i=sockfd+1 ;i<=maxfd ; i++){
            if(FD_ISSET(i,&rset)){
                char buffer[1024]={0};
                int count = recv(i,buffer,1024,0);
//连接结束,关闭连接
                if (count == 0){
                    INFO("client disconnect\n");
                    close(i);
                    FD_CLR(i,&rfds);
                    continue;
                }
                INFO("recv:%s,%d byte(s)\n",buffer,count);

                count = send(i,buffer,count,0);
                INFO("SEND:%d\n",count);
             }
        } 

poll方案

他的设计思想和select类似,也是将完整集合从用户态copy进内核态修改成就绪集合,不过它和select不同点他的结构体struct pollfd区分了events和revents,接受就绪集合,不会把原本的完整集合覆盖掉,这就意味着他不需要像select那样每轮复制一次集合

poll由一个结构体,多种时间标志,以及poll()函数组成,
struct pollfd:监控数组,每项包含fd,events,revents,每项仅包含该fd的关注事件和就绪事件
POLLIN,POLLOUT等:事件标识符
poll(fds, 数组项数, 超时毫秒数):等待就绪事件
实现代码如下

    struct pollfd fds[1024] = {0};
    fds[sockfd].fd = sockfd;
    fds[sockfd].events = POLLIN;

    int maxfd = sockfd;
    while(1){

        int nready = poll(fds,maxfd+1,-1);//fd集合,集合大小,超时
//入池判断,监听也是POLLIN,接受数据也是POLLIN
        if(fds[sockfd].revents & POLLIN){
            int clientfd = accept(sockfd,(struct sockaddr*)&client_addr,&len);
            INFO("accept finished:%d\n",clientfd);
//FD_SET(clientfd,&rfds);
            fds[clientfd].fd = clientfd;
            fds[clientfd].events = POLLIN;

            if(clientfd > maxfd)maxfd = clientfd;

        }
//遍历,执行
        int i=0;
        for(i=sockfd+1 ;i<=maxfd ; i++){
            if(fds[i].revents & POLLIN){
                char buffer[1024]={0};
                int count = recv(i,buffer,1024,0);
//断连:关闭连接,初始化fds[i]元素
                if (count == 0){//disconnect
                    INFO("client disconnect\n");
                    close(i);

                    fds[i].fd = -1;
                    fds[i].events = 0;

                    continue;
                }
                INFO("recv:%s,%d byte(s)\n",buffer,count);

                count = send(i,buffer,count,0);
                INFO("SEND:%d\n",count);
            }
        }
    }

epoll方案

作为Linux系统从2.5版本一直沿用至今的方案,linux能成为目前云服务器的主流选择,它功不可没
它的设计思想同前两者不同的地方在于它不需要把整个关注集合都copy到内核态中修改,取而代之的是直接把本轮就绪结果从内核传回到用户数组。这个epoll就像快递驿站一样存放已就绪的事件,将需要监听的套接字、新建的连接通过epollctl函数加入epoll,在epoll_wait()检测到就绪事件传回就执行,监听或者是收发数据

其组成主要有一个结构体和三个函数

  • struct epoll_event :events(关注事件),data(保存所有自定义信息,例如文件描述符,连接对象地址)
  • epoll_create1():创建
  • epoll_ctl():添加、修改、删除所需要的fd
  • epoll_wait():等待就绪事件,返回就绪数量并填充结果数组

实现代码如下

//创建epoll
    int epfd = epoll_create(1);
//创建struct epoll_event结构体存储关注套接字和关注事件
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = sockfd;
//连接入epoll
    epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);

    while(1){
//存储就绪事件
        struct epoll_event events[1024] = {0};
        epoll_wait(epfd,events,1024,-1);

        int i=0;
        for(i=0;i<1024;i++){
            int connfd = events[i].data.fd;
//就绪事件中存在监听套接字,创建新连接入epoll
            if(connfd == sockfd){
                int clientfd = accept(sockfd,(struct sockaddr*)&client_addr,&len);
                INFO("accept finished:%d\n",clientfd);

                ev.events = EPOLLIN;
                ev.data.fd = clientfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,clientfd,&ev);
//处理就绪事件
            }else if (events[i].events & EPOLLIN){
                char buffer[1024]={0};
                int count = recv(connfd,buffer,1024,0);
                if (count == 0){//disconnect
                    INFO("client disconnect\n");
                    close(connfd);
                    epoll_ctl(epfd,EPOLL_CTL_DEL,connfd,NULL);

                    continue;
                }
                INFO("recv:%s,%d byte(s)\n",buffer,count);

                count = send(connfd,buffer,count,0);
                INFO("SEND:%d\n",count);
                } 

        }
    }
相关文章
|
5天前
|
云安全 人工智能 运维
当攻击全面Agent化,你的安全防御能否跟上AI Speed?
多起客户侧AK泄露事件应急的真实观察
1248 4
|
28天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
9821 32
|
9天前
|
存储 人工智能 安全
千问办公官网入口网页版登录:qwenwork.cn 注册送2000积分、登录送100积分
阿里云千问办公(QwenWork)是AI智能工作平台,支持一句话生成PPT、表格、网页、视频及数据分析。个人免费版送2000积分+每日登录赠100分,含1GB存储、5个发布页;企业版198元/席/月起。阿里千问办公QwenWork官网:https://t.aliyun.com/U/0VCTGt 阿里AI工作平台,一句话完成数据分析、PPT 生成、视频剪辑、网页搭建等复杂任务
|
4天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
|
14天前
|
存储 人工智能 并行计算
大模型本地部署终端选型方法论:以 Qwen3.8-27B 为例的四档分层完整流程
本文提出一套大模型本地部署终端选型方法论:定约束、定档位、定框架、定参数四步决策法,配合入门、主力、质量、无损四档分层模型。以 Qwen3.8-27B 实测数据为例,逐环节解读显存、带宽、存储、散热、系统、预算等要素,给出面向不同预算的优选方案、决策自查清单与市场观察框架。文末前瞻 AI 笔记本的 CPU+GPU 与统一内存两条路线,论证四步决策法在新品类上的延续性。
|
6天前
|
Web App开发 人工智能 JavaScript
太猛了,一个月干到15W+,给大家推荐一个最近爆火的开源逆向工具:REA
REA(Reverse Engineer Anything)是近期爆火的开源AI逆向工具,4月发布,1个月内斩获15万+ Star。它让AI Agent无需源码即可分析二进制、APK、JS/Electron、HAR包等17类目标,自动反编译、生成可运行代码,并强制返回带证据与局限的结论。全本地执行,MIT协议,支持Hopper/Ghidra/IDA等引擎,一行命令即可上手。
653 1
太猛了,一个月干到15W+,给大家推荐一个最近爆火的开源逆向工具:REA
|
13天前
|
人工智能 JSON 自然语言处理
2026 年 Jev 决策模型深度拆解:原理解读、实战测评与保姆级落地教程
有一款特殊AI模型在开发者圈子刷屏,它摒弃传统大模型擅长的对话聊天能力,专注做高速结构化决策,它就是TypeSafe AI推出的Jev模型。该模型由ChatGPT共同发明人Diogo Almeida主导研发,定位为**System One Model(系统一模型)**,对标人类大脑快速直觉判断的思维模式,在响应延迟、调用成本、结构化输出稳定性上相比传统生成式大模型有着巨大差异。本文会完整拆解Jev底层原理、三大核心原语能力、适用业务场景,同时提供可直接运行的curl、Python代码示例,并且结合多组实测数据,客观分析模型优势与能力边界,帮助普通开发者和AI应用从业者快速上手落地。
956 1
|
10天前
|
人工智能 JSON 自然语言处理
2026 年 Jev 决策模型全解析:核心原理拆解,性能实战测评与落地部署教程
有一款特殊AI模型在开发者圈子刷屏,它摒弃传统大模型擅长的对话聊天能力,专注做高速结构化决策,它就是TypeSafe AI推出的Jev模型。该模型由ChatGPT共同发明人Diogo Almeida主导研发,定位为System One Model(系统一模型),对标人类大脑快速直觉判断的思维模式,在响应延迟、调用成本、结构化输出稳定性上相比传统生成式大模型有着巨大差异。本文会完整拆解Jev底层原理、三大核心原语能力、适用业务场景,同时提供可直接运行的curl、Python代码示例,并且结合多组实测数据,客观分析模型优势与能力边界,帮助普通开发者和AI应用从业者快速上手落地。
608 0

热门文章

最新文章