select、poll

linux中的select,poll两种都在select.c中实现,两者的结构相似,基本原理也相似,且底层有使用相同的结构体。

select参数有文件描述符的最大数+1,三种监视的事件的文件描述符位数组,分别是读事件,写事件,异常事件,还有一个超时时间。

poll的参数有一个数组,数组元素是struct pollfd,其中包含了所要监视的文件描述符和所要监视的事件。还有一个文件描述符的个数和一个超时事件,首先进入sys_poll中先进行检查n和超时时间,然后对回调函数poll_table进行初始化,再在内核中开辟空间一页或者数组长度大小的结点,然后将用户态的数据拷贝到内核态,链成链表,然后再调用do_poll、do_pollfd来对每一页每一个文件描述符进行检测是否有时间发生,如果有事件发生就将其链入等待队列,++count。返回到do_poll,然后判断是否有信号,是否超时,count即是否有事件产生,如果有的话就返回到sys_poll中,将内核中的事件拷贝到用户原来的数据上,返回给用户,然后由用户从头到尾进行检测。

/select server//  
[cpp] view plain copy
#include <stdio.h>  
#include <stdlib.h>  
#include <iostream>  
#include <sys/types.h>  
#include <fcntl.h>  
#include <unistd.h>  
using namespace std;  
#include <sys/time.h>  
#include <assert.h>  
#include <string.h>  
//struct timeval  
//{  
//  time_t tv_sec; 表示秒   
//  long tv_usec;毫秒  
//};  
  
//int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeout);  
//nfds是文件描述符中最大的加1  
int main()  
{  
    mkfifo("pipe1", 0666);  
    mkfifo("pipe2", 0666);  
    mkfifo("pipe3", 0666);  
      
    int fd1 = open("pipe1", O_RDONLY);  
    int fd2 = open("pipe2", O_RDONLY);  
    int fd3 = open("pipe3", O_RDONLY);  
      
    assert(fd1!=-1 && fd2!=-1 && fd3!=-1);  
      
    char buff[128];  
    int result;  
  
    fd_set inputs, testfds;//设置要监视的文件描述符数组  
    struct timeval timeout;//超时设置  
  
    FD_ZERO(&inputs);  
    FD_SET(fd1, &inputs);  
    FD_SET(fd2, &inputs);  
    FD_SET(fd3, &inputs);  
  
    while(1)  
    {  
        testfds = inputs;//每次都要对select中的监视文件描述符参数进行重置  
        timeout.tv_sec = 2;  
        timeout.tv_usec = 500000;//对时间参数进行重置  
  
        result = select(FD_SETSIZE, &testfds, (fd_set *)NULL, (fd_set *)NULL, &timeout);  
        //进行监视可读事件,如果有事件发生就返回发生事件的个数  
        //FD_SETSIZE的是表示最大数字加1  
        cout<<result<<endl;       
        if (result == 0)//超时  
        {  
            cout<<"timeout\n";  
        }  
        else if(result == -1)//出错,可以通过判断来鉴别出错具体内容  
        {  
            perror("error select");  
            exit(-1);  
        }  
        else//有数据可读  
        {  
            for (int fd=0; fd<FD_SETSIZE; ++fd)//遍历数组  
            {   
                if (FD_ISSET(fd, &testfds))//用文件符与之判断  
                {  
                    int num = read(fd, buff, 128);//由何处而知道该文件描述符的大小是?  
                    cout<<"from fd"<<fd<<"  buff is:"<<buff<<endl;  
                    if (strncmp(buff, "exit", 4) == 0)  
                    {  
                        exit(0);  
                    }  
                }  
            }  
        }  
    }  
    return 0;  
}  
  
//每次都要将数据从用户拷贝到内核  
//外设的操作都是通过内核来进行的,内核能最早知道哪个文件描述符发生事件  
//通过显示pipe来测试多文件描述符的监视<pre code_snippet_id="2373561" snippet_file_name="blog_20170504_2_9947800" name="code" class="cpp">///    select client //  
#include <stdio.h>  
#include <stdlib.h>  
#include <iostream>  
#include <sys/types.h>  
#include <fcntl.h>  
#include <unistd.h>  
using namespace std;  
#include <sys/time.h>  
#include <assert.h>  
#include <string.h>  
  
int main()  
{  
    int fd1 = open("./pipe1", O_WRONLY);  
    int fd2 = open("./pipe2", O_WRONLY);  
    int fd3 = open("./pipe3", O_WRONLY);  
    assert(fd1!=-1 && fd2!=-1 && fd3!=-1);  
    int fd = 0;  
      
    char buf[128];  
    while(1)  
    {  
        cout<<"input fd ";      
        scanf("%d", &fd);  
        getchar();//整型输入问题  
          
        fgets(buf, 128, stdin);  
        if(strncmp(buf, "exit", 4)==0){exit(0);}  
          
        switch(fd)  
        {  
            case 0:  
            {  
                cout<<"bye"<<endl;  
                write(fd1,"exit", 128);  
                close(fd1);  
                close(fd2);  
                close(fd3);  
                exit(0);  
            }  
            case 1:  
                write(fd1, buf, 128);  
                break;  
            case 2:  
                write(fd2, buf, 128);         
                break;  
  
            case 3:  
                write(fd3, buf, 128);             
                break;  
            defalute:  
                continue;  
        }  
        memset(buf,0,128);  
    }  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值