SOCKET编程中,select()函数的作用

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

    select()在SOCKET编程中还是比较重要的,可是对于初学SOCKET的人来说都不太爱用select()写程序,他们只是习惯写诸如 conncet()、accept()、recv()或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。可是使用select()就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况。如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。下面详细介绍一下!

    select()函数的格式(我所说的是Unix系统下的Berkeley Socket编程,和Windows下的有区别,一会儿说明):

    int select(int maxfdp,  fd_set* readfds,  fd_set* writefds,  fd_set* errorfds,  struct timeval* timeout);

    先说明两个结构体:

    第一:struct  fd_set可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),即文件句柄,这可以是我们所说的普通意义的文件,当然Unix下任何设备、管道、FIFO等都是文件形式,全部包括在内,所以,毫无疑问,一个socket就是一个文件,socket句柄就是一个文件描述符。fd_set集合可以通过一些由人为来操作,比如清空集合:FD_ZERO(fd_set*),将一个给定的文件描述符加入集合之中FD_SET(int,  fd_set*),将一个给定的文件描述符从集合中删除FD_CLR(int,  fd_set*),检查集合中指定的文件描述符是否可以读写FD_ISSET(int,  fd_set*)。一会儿举例说明。

    第二:struct timeval是一个大家常用的结构,用来代表时间值,有两个成员,一个是秒数另一个毫秒数

    具体解释select的参数:

    int maxfdp是一个整数值,是指集合中所有文件描述符的范围即所有文件描述符的最大值加1,不能错在Windows中这个参数值无所谓,可以设置不正确

    fd_set*  readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。

    fd_set*  writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。

    fe_set*  errorfds同上面两个参数的意图,用来监视文件错误异常

    struct timeval*  timeout是select的超时时间,这个参数至关重要,它可以使select处于三种状态

    第一:若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;

    第二:若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;

    第三:timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。

    返回值:

    负值:select错误

    正值:某些文件可读写或出错

    0:等待超时,没有可读写或错误的文件

    在有了select后可以写出像样的网络程序来!举个简单的例子,就是从网络上接受数据写入一个文件中。

    例子:

    int main()

    {

        int  sock;

        FILE*  fp;

        struct fd_set  fds;

        struct timeval  timeout = {3, 0};  //select 等待3秒,3秒轮询, 要非阻塞就置0

        char buffer[256] = {0};  //256字节的接收缓冲区

        /*假设已经建立UDP连接,具体过程不写,简单,当然TCP也同理,主机ip和port都已经给定,要写的文件已经打开

        sock = socket(...);

        bind(...);

        fp = fopen(...); */

        while(1)

        {

            FD_ZERO(&fds);  //每次循环都要清空,否则不能检测描述符变化

            FD_SET(sock,  &fds);  //添加描述符

            FD_SET(fp,  &fds);  //同上

            maxfdp = sock>fp?sock+1:fp+1;  //描述符最大值加1

            switch(select(maxfdp,  &fds,  &fds,  NULL,  &timeout))  //select使用

            {

                case -1: exit(-1); break;  //select错误,退出程序

                case  0: break;  //再次轮询

                default:

                    if(FD_ISSET(sock, &fds))  //测试sock是否可读,即是否网络上有数据

                    {

                        recvfrom(sock, buffer, 256, .... );  //接受网络数据

                        if(FD_ISSET(fp, &fds))  //测试文件是否可写

                        fwrite(fp, buffer...);  //写入文件

                        buffer清空;

                    }  //end if break 

            }  //end switch

        }  //end while

    }  //end main

 

 

 

 

 

 

 

 

 

select() 的 timeout 陷阱 在调用 select() 的 timeout 会倾向于在循环外部进行赋值,以降低不必要的 CPU 消耗,关于 select() timeout 上的用法陷阱,很多资深的平台移植人员也掉进过,在 FreeRTOS 平台调用 select,timeout 的值在调用前后保持不变,但任何的处理都是要花费时间的,当 select() 第一次调用完成再次进入循环体时,这个 timeout 的值已经背更新为”剩下的时间“,如 9 秒,这个时候,select() 调用的设计不再符合设计者的初衷, 阅读详情

相关推荐

C#下用select方法实现socket服务端

select是一种比较古老但一直被证明性能很好的socket模式,它可以让你以消息驱动的模式书写socket程序。网上C++的例子很多,但C#的例子极少。 上代码: namespace Server { class Program { // Thread signal. public static ManualResetEvent allDone = n

张天师的专栏 8750

socket通信中select函数的使用和解释

select函数作用:       select()SOCKET编程中还是比较重要的,可是对于初学SOCKET的人来说都不太爱用select()写程序,他们只是习惯写诸如 conncet()、accept()、recv()或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即...

weixin_33853827的博客 1234

c#网络通讯Select多路复用——小白笔记#8

一、关于Socket网络通讯,如果我们要同时监听多个客户端进行接收和发送消息时,直接使用Socket通讯的话就可能会出现其中一个Socket接收不到客户端发来的消息而阻塞而导致其他Socket阻塞,这就需要启用多个线程来监听每一个Socket,这样就会占用很多资源。为了解决这种问题,我们就要用到Select多路复用了,它能够同时监听多个Socket,如果一个Socket阻塞,其他Socket也能够正常运行,从而可以在一个线程中监听所有的Socket。为null时:一直阻塞直到前面三个发生变化时打开。

qq_65158315的博客 863

socket select函数用法,图文并茂讲解,初学者必备

Linux IO多路复用三剑客之select,图文并茂简介select实现原理和用法,初学者必备。

weixin_28673511的博客 3571

socket编程select()函数作用

select()SOCKET编程中还是比较重要的,可是对于初学SOCKET的人来说都不太爱用select()写程序,他们只是习惯写诸如 conncet()、accept()、recv()或recvfrom()这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。可是使用select()就可...

auspark的专栏 555

SOCKET编程中,select()函数作用

SelectSocket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。可是使用Select就可以完成非阻塞(所谓非阻塞方式

zhenxi_20的专栏 1733

SOCKET编程中,select()函数作用

转自https://zhidao.baidu.com/question/6530466.html?qbl=relate_question_3&word=select%D4%DAsocket SelectSocket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓

qingkongyeyue的博客 1157

SOCKET编程中.select()函数作用

转贴http://hi.baidu.com/f234f234/blog/item/982c9b225ab11af3d6cae259.html  急!!!急!!!求助!!有谁知道在SOCKET编程中,select()函数作用,最好有代码的2006-08-22 14:22急!!!急!!!求助!!有谁知道在SOCKET编程中,select()函数作用,最好

wdypwl的专栏 621

Socket编程select()的妙用

Socket编程select()的妙用发信站: 华南网木棉站 (Tue Aug 4 15:43:41 1998), 转信 【 原文由 cpu 所发表 】 用过 WinSock API 网友们知道:WinSock 编程中有一很方便的地方便是其 息驱动机制,不管是底层 API 的 WSAAsyncSelect() 还是 MFC 的异步Socket类: CAsy

蝈蝈俊.net 2617

LWIP学习之Socket (API篇)

Socket接口编程SocketSocket API1. socket()2.blind()3.listen()4.accept()5.读 read()、revel()6.写sendto()、send()、write()7.close()Socket Socket API 1. socket() 2.blind() 3.listen() 4.accept() 5.读 read()、revel() 6.写sendto()、send()、write() 7.close()、 ...

qq_39854159的博客 6459

linux中select()函数分析

SelectSocket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事

1166

Linux下C++进行socket连接,多进程+阻塞IO、select进行IO多路复用

同步阻塞(BIO)和Select IO多路复用

weixin_45089880的博客 622

select用于实现I/O多路复用

阻塞和非阻塞   阻塞函数在完成其指定的任务以前不允许程序调用另一个函数。例如,程序执行一个读数据的函数调用时,在此函数完成读 操作以前将不会执行下一程序语句。当服务器运行到accept语句时,而没有客户连接服务请求到来,服务器就会停止在accept语句上等待连接服务请求 的到来。这种情况称为阻塞(blocking)。而非阻塞操作则可以立即完成。比如,如果你希望服务器仅仅注意检查是否有客户在等...

yuanlanjun 164

socket编程常用API

典型的UDP客户/服务器程序的函数调用: 典型的TCP客户/服务器程序的函数调用: TCP可靠传输 2.bind() 绑定套接字与网络地址(把一个本地协议地址赋予一个套接字) 1.通用地址结构体的定义: 2.特殊地址结构体 —— IPv4 地址结构体: 3.特殊地址结构体 —— IPv6 地址结构体: 4.特殊地址结构体 ——UNIX 域地址结构体: 3.connect() 建立连接 调用connect前不必非得调用bind,如果没有bind,内核会确定源IP并选择一个临时端口作为源端口如果

qq_45698138的博客 4430

网络socket编程(一)——socket接口函数、面向数据报的UDP编程及测试、select函数应用

本文对网络编程接口socket进行了简单的阐述,并介绍了一些编程中常用的socket接口函数。后针对面向数据报的UDP进行实战编程和测试,分别实现了UDP客户端和服务端的编程,还针对UDP可能会丢包的缺陷在程序中调用select设置接收超时。测试工具使用SocketTool和UDP_tester,搭建测试环境,测试结果达到了预期的效果。

weixin_45389997的博客 2203

select()函数返回值及selectsocket阻塞的关系及select函数的意义

1、select()函数返回值 select的返回值与recv函数的返回值十分类似,都分>0,=0,<0三种情况。 >0:有事件发生, FD_ISSET(socket, &fd_read); recv()....... =0:timeout,超时 <0:出错。 在出错的情况下, 这三种错误下认为连接是正常的,继续接收 if(errno == EINTR ||(errno == EAGAIN)||errno == EWOU...

modi000的博客 2万+
上一篇: SOCKET编程之INADDR_ANY
下一篇: UDP SOCKET编程中的connect()
ixidof
博客等级 码龄19年 222粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值