网络编程 day04 (linux ) 函数: select ,poll

1.select (看代码!! 解释看不懂)

头文件:#include <sys/types.h>           

  #include <sys/time.h>             

  #include <unistd.h>

函数原型:int select (int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *tvptr);

返回值:准备就绪的描述符数,若超时则为0,若出错则为- 1 函数参数:

maxfd是需要监视的最大的文件描述符值+1;      

中间三个参数readfds(可读文件描述符集)、writefds(可写文件描述符集)和exceptfds (异常条件描述符集)是指向描述符集的指针。这三个描述符集说明了我们关心的可读、可写或处于异常条件的各个描述符。每个描述符集存放在一个fd_set数据类型中。

最后一个参数tvptr ,它指定愿意等待的时间。

struct timeval{ long tv_sec; /* seconds */

long tv_usec; /* and microseconds */ };

有三种情况: • tvptr == NULL:永远等待。如果捕捉到一个信号则中断此无限期等待。当所指定的描述符中的一个已准备好或捕捉到一个信号则返回。如果捕捉到一个信号,则select返回-1, errno设置为enter

• tvptr ->tv_sec == 0 && tvptr->tv_usec == 0:完全不等待。测试所有指定的描述符并立即返回。这是得到多个描述符的状态而不阻塞select函数的轮询方法。

• tvptr ->tv_sec != 0 && tvptr->tv_usec != 0 :等待指定的秒数和微秒数。当指定的描述符之一已准备好,或当指定的时间值已经超过时立即返回。如果在超时时还没有一个描述符准备好,则返回值是0,(如果系统不提供微秒分辨率,则tvptr->tv_usec值取整到最近的支持值。)与第一种情况一样,这种等待可被捕捉到的信号中断。


2.下面的宏提供了处理fd_set中的这三种描述词组的方式:

FD_CLR(int fd,fd_set* set);用来清除描述词组set中相关fd位

FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真

FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd位

FD_ZERO(fd_set *set)

用来清除描述词组set的全部位 以下列方式说明了一个描述符集后:

fd_set rset; int fd;

必须用F D Z E R O清除其所有位:

FD_ZERO (&rset); 然后在其中设置我们关心的各位:

FD_SET (fd,&rset);

FD_SET (STDIN_FILENO,&rset);

理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。

(1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。

(2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)

(3)若再加入fd=2,fd=1,则set变为0001,0011

(4)执行select(6,&set,0,0,0)阻塞等待

(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。

注意:没有事件发生的fd=5被清空。

select有三个可能的返回值。

(1) 返回值-1表示出错。这是可能发生的,例如在所指定的描述符都没有准备好时捕捉到一个信号。

(2) 返回值0表示没有描述符准备好。若指定的描述符都没有准备好,而且指定的时间已经超过,则发生这种情况。

(3) 返回一个正值说明了已经准备好的描述符数,在这种情况下,三个描述符集中仍旧打开的位是对应于已准备好的描述符位。

使用select的常见错误

1.当使用select时,1个最常见的编程错误是:忘了对最大描述字加1

2.忘了描述字集是值-结果参数,select返回时会将那些没准备好的bit置为0,所以如果要再次select时,一定要重新用FD_SET设置你感兴趣的描述字的对应bit

3.忘记重新填写timeout的值


3.  select  代码:

/************************************************************************************************************************************************************************************************************************
 *文件名:
 *作  者:She001
 *时  间:
 *版  本:
 *作  用:
****************************************************************************************************************************************************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<sys/select.h>
//目标:使用select监控	标准输入设备。
//参数1:所有描述符+1
//参数2:输入描述符集合
//参数3:输出描述符集合
//参数4:异常错误描述符集合
//参数5:超时时间设定
//返回值:已经准备好的描述符个数。如果没有 : 0 如果错误 -1;

//1.监控一个集合中的所有描述符。哪个描述符有动态,立即做出应答。描述符代表文件。
//2.操作时间到了也会做出反应。
//3.调用select会阻塞当前任务。
//结束select阻塞状态的原因:1,有描述符准备好了,2超时时间到。
//select函数结束时,都会清空时间结构体,三个描述符集合(只会剩下已经准备好的描述符):
//每调用一次select,都要重新填写超时时间+描述符。
//select基本用法
int main()
{
	fd_set rset = {0} ; 	//这个是描述符集合,把所有描述符放在这里面。
	struct timeval tm = {0} ; //设定超时时间

	int len = 0 ; //读到的长度
	char buff[128] = "";  //读到的内容
	int count = 0 ;

	while(strncmp(buff,"quit",4))
	{
		//把键盘文件添加到描述符号集合中
		FD_SET(STDIN_FILENO,&rset);
		tm.tv_sec =3;  //设定超时时间,如果3s内没有动静,就立刻返回
		count = select(STDIN_FILENO + 1,&rset,NULL,NULL,&tm);
		//有描述符准备好了。
		printf("count is  :%d\n",count);
		
		//可以监控这个文件描述符号集合中有几个有回应 有没有准备好。
		if(FD_ISSET(STDIN_FILENO,&rset))
		{
			fgets(buff,sizeof(buff),stdin);
			printf("readlen is  %s\n",buff);
		}
	}
	return 0 ;
}

4.poll 函数

 #include <poll.h>

 原型 : int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数:fds struct pollfd 类型的数据

nfds:说明fdarray数组中的元素数。

timeout:超时时间。若timeout==-1,则永远等待;若timeout==0,则不等待;若timeout>0,则等待timeout毫秒。 返回值:与select同。

poll提供了与select相似的功能,但当涉及到流设备时,它还提供附加信息。 #include <sys/poll.h> struct pollfd {    int fd;                / * 要检查状态的描述字 * /    

short int events;          / * 对于该描述字感兴趣的事件 * /    

short int revents;      / * 返回时,指出在该描述字上发生了什么事件 * /    };  


代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<sys/wait.h>
#include<a.out.h>
#include<signal.h>
#include<stdarg.h>
#include<sys/socket.h>
#include<utime.h>
#include<sys/utsname.h>
#include<sys/times.h>
#include<sys/un.h>
#include<ctype.h>
#include<dirent.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<syslog.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/time.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<sys/select.h>
#include <poll.h>

int main()
{
	//定义一个POLL结构体数组,一个成员
	struct pollfd pfds[1] = {1};
	//监控标准输入设备
	pfds[0].fd = STDIN_FILENO;
	//输入事件
	pfds[0].events = POLLIN;

	char buff[20] = "";
	int count = 0 ;
	while(1)
	{
		//描述符 数组 + 要监控的个数 +超时时间
		count = poll(pfds,1,3000);//毫秒单位	
		printf("count is %d\n",count);
		//结果事件是输入事件
		if(pfds[0].revents == POLLIN)
		{
			bzero(buff,sizeof(buff));
			fgets(buff,sizeof(buff),stdin);
			printf("buff = %s\n",buff);
			count = 0 ;
			printf("count is %d\n",count);
		}
	}

	return 0 ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值