【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了)

02-29 阅读 0评论

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀

【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了),【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了),词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,安装,第1张
(图片来源网络,侵删)

🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭

🤣本文内容🤣:🍭介绍select函数 🍭

😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭

⏰发布时间⏰:2024-02-01 17:19:49

本文未经允许,不得转发!!!

目录

  • 🎄一、概述
  • 🎄二、select 函数介绍
  • 🎄三、select 函数使用步骤
  • 🎄四、select 函数使用例子
  • 🎄五、pselect 函数及例子
  • 🎄六、总结

    【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了)

    【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了),【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了),词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,安装,第3张
    (图片来源网络,侵删)

    🎄一、概述

    在Unix / Linux系统中,有五种IO模型:阻塞I/O模型、非阻塞I/O模型、复用式I/O模型、信号驱动式I/O模型、异步I/O模型。其中,复用式I/O模型的实现方式之一就是使用select函数来阻塞等待内核准备好数据,等数据准备好了之后,再通知应用层的进程调用IO操作函数来获取数据。

    【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了)

    下面将介绍select函数以及select函数的使用方法。


    【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了)

    🎄二、select 函数介绍

    select 函数原型:

    #include 
    #include 
    int select(int nfds, fd_set *readfds, fd_set *writefds,
                      fd_set *exceptfds, struct timeval *timeout);
    

    select允许调用进程监视多个文件描述符,等待一个或多个文件描述符的I/O操作(读、写、异常)准备就绪。准备就绪是指该描述符执行相应的I/O操作(读、写、异常)不会等待(阻塞)了,可以直接返回。

    【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了),【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了),词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,安装,第6张
    (图片来源网络,侵删)

    参数说明:

    • nfds:填一个描述符数值,该数值等于三个集合(readfds、writefds、exceptfds)中最大文件描述符加1。

      例如:readfds、writefds、exceptfds中最大的描述符是58,则nfsd就填59。

    • readfds:传入传出参数,要监视的进行读取操作的描述符集合;
    • writefds:传入传出参数,要监视的进行写取操作的描述符集合;
    • exceptfds:传入传出参数,要监视的可能出现异常的描述符集合;
    • timeout:该参数指定select函数应阻止等待文件描述符准备就绪的时间间隔。这个参数有三种可能:
      • 1、timeout设置为NULL:一直阻塞等待,直到有描述符准备就绪;
      • 2、timeout设置一定的时间:阻塞等待timeout设置的时间,期间有描述符准备就绪就返回,没有就等到时间结束返回。
      • 3、timeout设置的时间为0:不等待,检查描述符后直接返回。

        返回值:成功返回已准备就绪的描述符数,且对应的描述符集会返回已准备就绪的描述符;超时返回0;失败返回-1。


        【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了)

        🎄三、select 函数使用步骤

        select函数的使用步骤主要分成4步,前3步是为了调用函数,第4步是检查我们刚兴趣的描述符是否准备就绪:

        • 1、添加感兴趣的描述符到对应的描述符集;

          这个主要针对select函数中间的三个参数,它们都是fd_set类型的,可以使用下面4个宏来操作该类型:

          void FD_CLR(int fd, fd_set *set);	// 从描述符集删除 fd
          int  FD_ISSET(int fd, fd_set *set);	// 检查描述符集是否包含了 fd
          void FD_SET(int fd, fd_set *set);	// 设置 fd 到描述符集
          void FD_ZERO(fd_set *set);			// 清空描述符集
          
        • 2、计算出所添加的所有描述符中最大的描述符,把该描述符加1,设置到select函数的第一个参数;

        • 3、根据需求设置等待时长。

          struct timeval {
             time_t      tv_sec;     // seconds
             suseconds_t tv_usec;    // microseconds-微秒
          };
          
        • 4、函数成功返回后,如果有准备就像的描述符,会从设置的描述符集中返回。可以调用宏FD_ISSET来检查哪个描述符准备就像。


          【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了)

          🎄四、select 函数使用例子

          下面使用TCP套接字来演示select的使用例子,如果要执行的话,分别保存服务端、客户端代码为select_tcpSer.c、select_tcpCli.c,然后执行下面代码编译:

          gcc select_tcpSer.c -o ser 
          gcc select_tcpCli.c -o cli
          

          然后先在一个命令行窗口运行服务端./ser,再重新打开一个命令行窗口运行客户端./cli。下面是服务端的运行结果:

          【Linux C | I/O模型】IO复用 | select、pselect函数详解(看完就会用了)


          TCP服务端代码如下:使用select阻塞等待可读描述符返回。

          #include 
          #include 
          #include 
          #include 
          #include 
          #include 
          #include 
          int select_wait(int listenFd, int connFd[10], int connNum)
          {
          	// 1、添加感兴趣的描述符到可读描述符集
          	fd_set read_set;
          	FD_ZERO(&read_set);
          	FD_SET(listenFd, &read_set);
          	int i = 0;
          	for(i=0; i
          		FD_SET(connFd[i], &read_set);
          	}
          	
          	// 2、计算出最大描述符
          	int maxFd = listenFd;
          	for(i=0; i
          		if(connFd[i]maxFd)
          			maxFd = connFd[i];
          	}
          	maxFd++;
          	
          	// 3、设置等待时长2分钟
          	struct timeval timeout;
          	timeout.tv_sec = 2*60;
          	timeout.tv_usec= 0;
          	
          	int ret = select(maxFd, &read_set, NULL, NULL, &timeout);// 阻塞等待
          	if(ret  0)// 即使有多个fd可读,我们也只返回一个描述符,其他的下次处理
          	{
          		printf("success, Number of descriptors returned is %d\n", ret);
          		if(FD_ISSET(listenFd, &read_set))
          		{
          			return listenFd;
          		}
          		
          		for(i=0; i
          			if(FD_ISSET(connFd[i], &read_set))
          			{
          				return connFd[i];
          			}
          		}
          	}
          	else if(ret == 0)
          	{
          		printf("select timeout\n");
          	}
          	return -1;
          }
          int del_connfd(int connFds[10], int connNum, int delFd) // 从connFds数组中删除delFd
          {
          	int tmpFds[10]={0,};
          	int i = 0, index = 0;;
          	memcpy(tmpFds, connFds, connNum*sizeof(connFds[0]));
          	for(i=0; i
          		if(tmpFds[i] != delFd)
          		{
          			connFds[index++] = tmpFds[i];
          		}
          	}
          	return index;
          }
          int main()
          {
          	// 1、创建TCP套接字socket
          	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
          	if(sockfd
          		perror("socket error" );
          		return -1;
          	}
          	
          	// 2、准备服务端ip和端口
          	struct sockaddr_in servaddr;
          	bzero(&servaddr, sizeof(servaddr));
          	servaddr.sin_family = AF_INET;
          	servaddr.sin_port = htons (10086);
          	servaddr.sin_addr.s_addr = INADDR_ANY; // 指定ip地址为 INADDR_ANY,这样要是服务器主机有多个网络接口,服务器进程就可以在任一网络接口上接受客户端的连接
          	
          	// 3、绑定 bind
          	if (bind(sockfd,(struct sockaddr*)&servaddr, sizeof(servaddr)) 

免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,人围观)

还没有评论,来说两句吧...

目录[+]