zoukankan      html  css  js  c++  java
  • IO复用——select系统调用

    1、select函数

        此函数用于在一段时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等事件。

    #include<sys/select.h>
    int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout)
    • nfds参数指示被监听的文件描述符总数。通常设置为最大文件描述符值+1,因为文件描述符从0开始计数
    • readfds、writefds和exceptfds参数分别指可读、可写和异常事件对应的文件描述符集合。函数返回时,内核将修改它们来通知应用程序已经就绪的文件描述符。在下次调用select之前,需要重新设置文件描述符。
    • timeout参数指定超时时间。使用指针,内核可以通过修改此值来告诉应用程序函数等待的时间,但是调用失败时,此值不确定。如果传入结构内的成员都为0,则函数立即返回;如果传入NULL,则函数一直阻塞,直到有文件描述符就绪。
    • 函数成功返回时,返回就绪的文件描述总数;超时时间内没有文件描述符就绪,就返回0;失败返回-1并设置errno;如果在函数等待期间,程序接收到信号,则select立即返回-1,并置errno为EINTR。

        fd_set结构体中是一个整型数组,该数组中的每一个元素的每一位标识一个文件描述符。fd_set能容纳的文件描述符数量由FD_SETSIZE指定。使用下列宏来访问fd_set结构体中的位:

    FD_ZERO(fd_set* fdset)              //清除fdset的所有位
    FD_SET(int fd, fd_set* fdset)       //设置fdset的fd位
    FD_CLR(int fd, fd_set* fdset)       //清除fdset的fd位
    int FD_ISSET(int fd, fd_set* fdset) //检测fdset的位fd是否被置位

        struct timeval结构定义如下:

    struct timeval
    {
        long tv_sec;   //秒数
        long tv_usec;  //微秒数
    }

    2、网络编程中文件描述符就绪条件

        可读:

    • socket内核接收缓冲区中的字节数大于或等于其低水位标记SO_RCVLOWAT,此时可无阻塞的读socket,读操作返回值大于0
    • socket通信对方关闭连接,此时读该socket将返回0
    • 监听socket上有新的连接请求
    • socket上有未处理的错误,此时可调用getsockopt来读取和清除错误

        可写:

    • socket内核发送缓冲区中的可用字节数大于或等于其低水位标记SO_SNDLOWAT,此时可无阻塞的写socket,写操作返回值大于0
    • socket的写操作被关闭,对写操作被关闭的socket执行写操作将触发一个SIGPIPE信号
    • socket使用非阻塞connect连接成功或者失败(超时)之后
    • socket上有未处理的错误,此时可调用getsockopt来读取和清除错误

    3、select异常处理

        select能处理的异常只有一种,即socket上接收到带外数据。带外数据的处理可参见下面的程序示例。

    4、程序示例

    void worker(int connfd)  //参数为与客户侧连接的socket
    {
    	char buf[1024];
    	fd_set read_fds;
    	fd_set exception_fds;
    	FD_ZERO(&read_fds);
    	FD_ZERO(&exception_fds);
    
    	while(1)
    	{
    		memset(buf, 0, sizeof(buf));
    		FD_SET(connfd, &read_fds);
    		FD_SET(connfd, &exception_fds);
    		ret = select(connfd + 1, &read_fds, NULL, &exception_fds, NULL);
    		if(ret < 0)
    		{
    			printf("select fail
    ");
    			break;
    		}
    
    		if(FD_ISSET(connfd, &read_fds))
    		{
    			ret = recv(connfd, buf, sizeof(buf)-1, 0);
    			if(ret <= 0)
    			{
    				break;
    			}
    			
    			//处理数据代码
    			
    		}
    		//对于异常事件,采用带MSG_OOB标志的recv函数来读取带外数据
    		else if(FD_ISSET(connfd, &exception_fds))
    		{
    			ret = recv(connfd, buf, sizeof(buf)-1, MSG_OOB);
    			if(ret <= 0)
    			{
    				break;
    			}
    
    			//处理带外数据代码
    			
    		}
    	}
    	close(connfd);
    	return;
    }

  • 相关阅读:
    JS高级-虚拟DOM
    JS高级-异步
    tomcat server.xml中文版
    java中的等于
    eclipse version
    angularjs中父,子,兄之间controller值得传递
    《那一天,那一月,那一年,那一世》-------仓央嘉措
    用jsonp格式的数据进行ajax post请求变成get
    git常用指令
    让div支持placeholder属性/模拟输入框的placeholder属性
  • 原文地址:https://www.cnblogs.com/fangyan5218/p/10618256.html
Copyright © 2011-2022 走看看