zoukankan      html  css  js  c++  java
  • select()

    //int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);
    //参数1 描素符的总数 它比所有文件描述符集合中的文件描述符的最大值大1, readfds、writefds、exceptset:分别指向可读、可写和异常等事件对应的描述符集合。timeout:用于设置select函数的超时时间,即告诉内核select等待多长时间之后就放弃等待。timeout == NULL 表示等待无限长的时间
    
    
    服务器上sizeof(fd_set)=512,每bit表示一个文件描述符,则我服务器上支持的最大文件描述符是512*8=4096。
    #include <sys/select.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    
    
    int main()
    {
        fd_set rd;  //结构体
        struct timeval tv;  //结构体
        int err;
    
    
    
    
        FD_ZERO(&rd);  //初始化放到_fd_set 变量
        FD_SET(0,&rd);  //把标准输入 放入rd中
    
    
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        err = select(1,&rd,NULL,NULL,&tv);
    
    
        if(err == 0) //超时
        {
            printf("select time out!
    ");
        }
        else if(err == -1)  //失败
        {
            printf("fail to select!
    ");
        }
        else  //成功
        {
            printf("data is available!
    ");
        }
        char ch;
        while(ch=getchar()!='
    ');
        return 0;
    }
    
    
    
    
    #include <stdio.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <fcntl.h>
    #include <stdlib.h>
    
    
    
    
    int main(int argc, char* argv[])
    {
        if(argc <= 2)
        {
            printf("usage: ip address + port numbers
    ");
            return -1;
        }
     struct timeval tv;
        const char* ip = argv[1];
        int port = atoi(argv[2]);
        tv.tv_sec = 5;
        tv.tv_usec = 0;
            printf("ip: %s
    ",ip);
            printf("port: %d
    ",port);
    
    
        int ret = 0;
        struct sockaddr_in address;
        bzero(&address,sizeof(address));
        address.sin_family = AF_INET;
        inet_pton(AF_INET,ip,&address.sin_addr);
        address.sin_port = htons(port);
    
    
        int listenfd = socket(PF_INET,SOCK_STREAM,0);
        if(listenfd < 0)
        {
            printf("Fail to create listen socket!
    ");
            return -1;
        }
    
    
        ret = bind(listenfd,(struct sockaddr*)&address,sizeof(address));
        if(ret == -1)
        {
            printf("Fail to bind socket!
    ");
            return -1;
        }
    
    
        ret = listen(listenfd,5); //监听队列最大排队数设置为5
        if(ret == -1)
        {
            printf("Fail to listen socket!
    ");
            return -1;
        }
    
    
        struct sockaddr_in client_address;  //记录进行连接的客户端的地址
        socklen_t client_addrlength = sizeof(client_address);
        int connfd = accept(listenfd,(struct sockaddr*)&client_address,&client_addrlength);
        if(connfd < 0)
        {
            printf("Fail to accept!
    ");
            close(listenfd);
        }
    
    
        char buff[1024]; //数据接收缓冲区
        fd_set read_fds;  //读文件操作符
        fd_set exception_fds; //异常文件操作符
        FD_ZERO(&read_fds);
        FD_ZERO(&exception_fds);
    
    
        while(1)
        {
            memset(buff,0,sizeof(buff));
            //每次调用select之前都要重新在read_fds和exception_fds中设置文件描述符connfd,因为事件发生以后,文件描述符集合将被内核修改
            FD_SET(connfd,&read_fds);
            FD_SET(connfd,&exception_fds);
    
    
            ret = select(connfd+1,&read_fds,NULL,&exception_fds,&tv);
            if(ret < 0)
            {
                printf("Fail to select!
    ");
                return -1;
            }
    
    
    
    
    
    
            if(FD_ISSET(connfd, &read_fds))
            {
                ret = recv(connfd,buff,sizeof(buff)-1,0);
                if(ret <= 0)
                {
                    break;
                }
    
    
                printf("get %d bytes of normal data: %s 
    ",ret,buff);
    
    
            }
            else if(FD_ISSET(connfd,&exception_fds)) //异常事件
            {
                ret = recv(connfd,buff,sizeof(buff)-1,MSG_OOB);
                if(ret <= 0)
                {
                    break;
                }
    
    
                printf("get %d bytes of exception data: %s 
    ",ret,buff);
            }
    
    
        }
    
    
        close(connfd);
        close(listenfd);
    
    
    
    
        return 0;
    }
    
    
    select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。这样所带来的缺点是:
    
    
    1、单个进程可监视的fd数量被限制,即能监听端口的大小有限。一般来说这个数目和系统内存关系很大,具体数目可以cat/proc/sys/fs/file-max察看。32位机默认是1024个。64位机默认是2048.
    
    
    2、 对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低:当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。
    
    
    3、需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大。
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <netinet/in.h>
    #include <sys/time.h>
    #include <sys/ioctl.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    
    int main()
    {
        int server_sockfd, client_sockfd;
        int server_len, client_len;
        struct sockaddr_in server_address;
        struct sockaddr_in client_address;
        int result;
        fd_set readfds, testfds;
        server_sockfd = socket(AF_INET, SOCK_STREAM, 0);//建立服务器端socket
        server_address.sin_family = AF_INET;
        server_address.sin_addr.s_addr = htonl(INADDR_ANY);
        server_address.sin_port = htons(8888);
        server_len = sizeof(server_address);
        bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
        listen(server_sockfd, 5); //监听队列最多容纳5个
    
    
    
    
        FD_ZERO(&readfds); //初始化文件描素符集合
        FD_SET(server_sockfd, &readfds);//将服务器端socket加入到集合中
        while(1)
        {
            char ch;
            int fd;  //用于循环
            int nread;
            testfds = readfds;//将需要监视的描述符集copy到select查询队列中,select会对其修改,所以一定要分开使用变量
            printf("server waiting
    ");
    
    
            /*无限期阻塞,并测试文件描述符变动  FD_SETSIZE==1024*/
            result = select(FD_SETSIZE, &testfds, (fd_set *)0,(fd_set *)0, (struct timeval *) 0); //FD_SETSIZE:系统默认的最大文件描述符
            if(result < 1)
            {
                perror("server5");
                exit(1);
            }
    
    
            /*扫描所有的文件描述符*/
            for(fd = 0; fd < FD_SETSIZE; fd++)
            {
                /*找到相关文件描述符*/
                if(FD_ISSET(fd,&testfds))
                {
                  /*判断是否为服务器套接字,是则表示为客户请求连接。*/
                    if(fd == server_sockfd)
                    {
                        client_len = sizeof(client_address);
                        client_sockfd = accept(server_sockfd,
                        (struct sockaddr *)&client_address, &client_len);
                        FD_SET(client_sockfd, &readfds);//将客户端socket加入到集合中
                        printf("adding client on fd %d
    ", client_sockfd);
                        printf("ip,port%ld
    ",client_address.sin_port);
                    }
                    /*客户端socket中有数据请求时*/
                    else
                    {
                        ioctl(fd, FIONREAD, &nread);//取得数据量交给nread
    
    
                        /*客户数据请求完毕,关闭套接字,从集合中清除相应描述符 */
                        if(nread == 0) //
                        {
                            close(fd);
                            FD_CLR(fd, &readfds); //去掉关闭的fd
                            printf("removing client on fd %d
    ", fd);
                        }
                        /*处理客户数据请求*/
                        else
                        {
                            read(fd, &ch, 1);
                            sleep(5);
                            printf("serving client on fd %d
    ", fd);
                            ch++;
                            write(fd, &ch, 1);
                        }
                    }
                }
            }
        }
    
    
        return 0;
    }
    */
  • 相关阅读:
    阅读prettytable 一些代码、get、set 检查参数
    python 库 PrettyTabble 使用与错误
    python 内建模块与第三方模块
    python 排序 堆排序
    python 排序 桶排序
    python 排序冒泡排序与双向冒泡排序
    python 函数式编程 闭包,返回一个函数
    python 排序 选择排序
    python 排序 归并排序
    python 排序 插入排序与希尔排序
  • 原文地址:https://www.cnblogs.com/countryboy666/p/10970517.html
Copyright © 2011-2022 走看看