IO复用-Select

函数原型:

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

经典的Unix select系统调用:

for(   ;;   )
{
        tv.tv_sec   =   30;      
        tv.tv_usec   =   0;    
        FD_ZERO(   &rfds   );
        FD_SET(   sockfd,   &rfds   );

        switch(   ret   =   select(   sockfd   +   1,   &rfds,   NULL,   NULL,   &tv   )   )
        {
        case   0:
                  return   TIMEOUT;
        case   -1:
                  if   (   (errno   ==   EINTR)   )
                            continue;
                  return   BROKEN;
        default:
                  if   (   FD_ISSET(   sockfd,   &rfds   )   )
                  {
                        ...
                  }
        }
}

阻塞与非阻塞的理解:

所谓阻塞方式(block),顾名思义,就是进程或是线程执行到这些函数时,必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回。

所谓非阻塞方式 (non-block),就是进程或线程执行此函数时,不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况。
Tip:
若事件发生,则与阻塞方式相同;若事件没有发生,则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高

代码示例:

main()
{
	int sock;
	FILE *fp;
	struct fd_set fds;
	struct timeval timeout={3,0}; //select等待3秒,3秒轮询,要非阻塞就置0
	char buffer[256]={0}; //256字节的接收缓冲区

	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

你可能感兴趣的:(UNIX网络编程)