再次一起来玩linux select函数------可以用任何描述符号fd而不限于网络socket

972 篇文章 329 订阅
148 篇文章 34 订阅

          在之前的网络编程中, 我们经常提到select函数, Windows select和linux select大同小异, 下面, 我们来玩玩linux select, 直接上菜:

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/time.h>
#include<sys/types.h>

int main()
{
    struct timeval tv;              // 超时时间
	tv.tv_sec = 10;
    tv.tv_usec = 500;               // 注意单位是微秒

    fd_set rdfds;
    FD_ZERO(&rdfds);                // 描述集初始化
    FD_SET(STDIN_FILENO, &rdfds);   // STDIN_FILENO是标准输入, 塞入描述集

    int iRet = select(STDIN_FILENO + 1, &rdfds, NULL, NULL, &tv);  // 第一个参数是监控句柄号+1
    if(iRet < 0)
	{
		printf("selcet error, iRet %\n", iRet);
		return -1;
	}

   	if(0 == iRet)
	{
		printf("timeout \n");
		return -2;
	}

	printf("iRet = %d \n", iRet);                      // 在终端中, 输入, 然后按enter, 会走到这里

	char szBuf[10]= {0};
    if(FD_ISSET(STDIN_FILENO, &rdfds) ) 		       // 监控输入描述符已经发生了改变
	{ 
		printf("to read data\n");
		read(STDIN_FILENO, szBuf, sizeof(szBuf) - 1);  // 从键盘读取输入
    }
	
	write(STDOUT_FILENO, szBuf, strlen(szBuf));        // 在终端中回显
	return 0;
}

          执行程序后, 程序卡在select处, 如果用户不输入任何东西, 那么就会在10s + 500微秒的时候, select返回0.   如果用户在超时之前输入, 那么select立即返回1. 有点意思, 从这个程序可以体会到select的用途。

 

         在linux中, select函数也可以用来做延时程序哦, 精确度为微秒。爽。

 

         为了更好地理解上面的程序, 我们继续来看一个有趣的问题:

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/time.h>
#include<sys/types.h>

int main()
{
    struct timeval tv;              // 超时时间
	tv.tv_sec = 10;
    tv.tv_usec = 500;               // 注意单位是微秒

    fd_set rdfds;
    FD_ZERO(&rdfds);                // 描述集初始化
    FD_SET(STDIN_FILENO, &rdfds);   // STDIN_FILENO是标准输入, 塞入描述集
	FD_SET(STDOUT_FILENO, &rdfds);  // STDOUT_FILENO是标准输入, 塞入描述集

	if(FD_ISSET(STDIN_FILENO, &rdfds) )
	{ 
		printf("STDIN_FILENO is in fds 111\n");
    }
	
	if(FD_ISSET(STDOUT_FILENO, &rdfds) )
	{ 
		printf("STDOUT_FILENO is in fds 222\n");
    }
	
    int iRet = select(STDIN_FILENO + 1, &rdfds, NULL, NULL, &tv);  // 第一个参数是监控句柄号+1
    if(iRet < 0)
	{
		printf("selcet error, iRet %\n", iRet);
		return -1;
	}

   	if(0 == iRet)
	{
		printf("timeout \n");
	}

	printf("iRet = %d \n", iRet); 

	if(FD_ISSET(STDIN_FILENO, &rdfds) )
	{ 
		printf("STDIN_FILENO is in fds   333\n");
    }
	
	if(FD_ISSET(STDOUT_FILENO, &rdfds) )
	{ 
		printf("STDOUT_FILENO is in fds  444\n");
    }
	
	return 0;
}

         运行一下, 然后什么也不要动(等10s中), 结果为:

 

STDIN_FILENO is in fds 111
STDOUT_FILENO is in fds 222
timeout 
iRet = 0 

         可见, 刚开始时候, 标准输入、标准输出描述符都在描述集中。 select函数在超时时间内, 没有检测到有输入输出, 此时这两个描述集被自动清除。 我们再次运行程序, 并在10s内输入数据, 可以看到, 结果为:

STDIN_FILENO is in fds 111
STDOUT_FILENO is in fds 222
iRet = 1 
STDIN_FILENO is in fds   333

        可以看到, 检测到有输入后, select函数立即返回, 此时标准输入描述符仍然在描述集中, 而标准输出描述集则被清除。 有点意思。

        所以, 在调用select之前, 我们通常需要把待监测的描述符号放下描述集中, 而在select后, 用FD_ISSET检查哪些描述符仍在描述集中, 那么, 这些描述集就处于就绪状态。 因此, select前后的操作均不可少。

       因此, 如下试好习惯和范式:

       FD_ZERO

       FD_SET

       select

       FD_ISSET

 

       最后要注意, 上述iRet为1表示rdfds中, 就绪的描述符总个数为1.

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值