操作系统——网络通信——多路复用——select 、poll 、epoll的函数的相关使用

本文介绍了Linux服务器网络通信中常用的多路复用技术,包括select、poll和epoll函数的使用。多路复用允许一个进程通过单个线程监控多个文件描述符,常用于TCP服务端。文章详细讲解了这些函数的工作原理、优缺点及应用场景,并给出了示例代码。

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

多路复用:

    使用一个进程(且只有主线程)同时监控若干个文件描述符的读写情况,这种读写模式称为多路复用

    多用于TCP的服务端,用于监控客户端的连接和数据的发送

    优点:不需要频繁的创建、销毁进程,从而节约了内存资源、时间资源,也避免了进程之间的竞争、等待

    缺点:要求单个客户端的任务不能太多于耗时,否则其他客户端就会感知到卡顿

    适合并发量高、但是任务量短小的情景,例如:Web服务器

    相关函数:

    select:

        fd_set  是文件描述符的集合,使用以下函数操作

        void FD_CLR(int fd, fd_set *set);

        功能:从集合set中删除fd文件描述符

        int  FD_ISSET(int fd, fd_set *set);

        功能:判断集合set中是否存在fd文件描述符

        void FD_SET(int fd, fd_set *set);

        功能:向集合set中添加fd文件描述符

        void FD_ZERO(fd_set *set);

        功能:清空集合set


 

        int select(int nfds, fd_set *readfds, fd_set *writefds,

                  fd_set *exceptfds, struct timeval *timeout);

        功能:同时监控多个文件描述的读、写、异常操作

        nfds:被监控的文件描述符中的最大值+1

        readfds:监控读操作的文件描述符集合

        writefds:监控写操作的文件描述符集合

        exceptfds:监控异常操作的文件描述符集合

        timeout:设置超时时间

            NULL        一直阻塞,直到某个文件描述符发生了变化

            0秒0微秒    非阻塞

            大于0秒     等待超时时间,超时返回0

            struct timeval {

               time_t         tv_sec;     //秒

               suseconds_t    tv_usec;    //微秒

           };

        返回值:监控到发生相关操作的文件描述符的个数,超时返回0

        错误返回-1

        注意:

            readfds、writefds、exceptfds 这三个集合参数既是输入也是输出,

            调用select时这三个集合需要存储被监控的见闻描述符,当由于有文件描述符发生了相应的操作而导致函数返回时,这三个集合中

            存储了这些文件描述符并返回给调用者

        select设计不合理的地方:

            1、每次调用select都需要向它重新传递被监控的文件描述符集合

            2、调用结束后如果想知道具体是哪个文件描述符发生了相关操作,必须把所有被监控的文件描述符进行一遍测试

        select的优点:

            它是最早的多路复用函数,几乎所有的操作系统都支持,兼容性很高


 

        #include <stdio.h>

        #include <stdlib.h>

        #include <string.h>

        #include <unistd.h>

        #include <sys/socket.h>

        #include <sys/types.h>

        #include <netinet/in.h>

        #include <arpa/inet.h>

        #include <sys/select.h>

        //  TCP server

        typedef struct sockaddr* SP;

        int main(int argc,const char* argv[])

        {

            int sockfd = socket(AF_INET,SOCK_STREAM,0);

            if(0 > sockfd)

            {

                perror("socket");

                return EXIT_FAILURE;

            }

            struct sockaddr_in addr = {};

            addr.sin_family = AF_INET;

            addr.sin_port = htons(5566);

            addr.sin_addr.s_addr = inet_addr("127.0.0.1");

            socklen_t addrlen = sizeof(addr);

            if(bind(sockfd,(SP)&addr,addrlen))

            {

                perror("bind");

                return EXIT_FAILURE;

            }

            if(listen(sockfd,10))

            {

                perror("listen");

                return EXIT_FAILURE;

            }

            //  定义读操作文件描述符集合

            fd_set reads;

            FD_ZERO(&reads);

            //  把等待连接的sockfd添加到集合

            FD_SET(sockfd,&reads);

            //  定义超时时间

            struct timeval timeout = {5,0};

            //  定义记录集合中最大值fd的变量

            int max_fd = sockfd;

            char buf[4096] = {};

            size_t buf_size = sizeof(buf);

         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaoyu1381

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值