• poll函数


     poll函数与select函数的功能基本一样,其定义如下:

    #include <poll.h>

    int poll(struct pollfd fds[], nfds_t nfds, int timeout);

    参数说明:

    struct pollfd{

      int fd;              //文件描述符

      short events;    //请求的事件

      short revents;   //返回的事件

      };

    fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于 socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select() 函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因 此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况

    nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;

    timeout:是poll函数调用阻塞的时间,单位:毫秒;

            poll() 函数不会受到socket描述符上的O_NDELAY标记和O_NONBLOCK标记的影响和制约,也就是说,不管socket是阻塞的还是非阻塞 的,poll()函数都不会收到影响;而select()函数则不同,select()函数会受到O_NDELAY标记和O_NONBLOCK标记的影 响,如果socket是阻塞的socket,则调用select()跟不调用select()时的效果是一样的,socket仍然是阻塞式TCP通讯,相 反,如果socket是非阻塞的socket,那么调用select()时就可以实现非阻塞式TCP通讯;

    #include<stdio.h>
    #include<stdlib.h>
    #include<errno.h>
    #include<string.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<sys/un.h>
    #include<sys/wait.h>      //*进程用的头文件*/
    #include<netinet/in.h>
    #include<arpa/inet.h>
    #include<unistd.h>
    #include<poll.h>        //包含poll的头文件
    
    #define MAXLINE  1024  //通信内容的最大长度
    
    #ifndef FD_SETSIZE
    #define FD_SETSIZE 25  //select最多能处理的文件描述符
    #endif
    
    ssize_t readn(int fd, void *buf, size_t count)
    {
        ssize_t nleft=count;
        ssize_t nread;
        char *charbuf=(char*) buf;
    
        while(nleft>0)
        {
            nread=read(fd,charbuf,nleft);
            if(nread<0)
              {
                  if(errno==EINTR)
                   continue;
                            return -1;
              }
            else if(nread==0)
                           return count-nleft;
                    
            charbuf +=nread;
                    nleft=count-nread;
        }
        return count;    
    }
    
    ssize_t writen(int fd, const void *buf, size_t count)
    {
            ssize_t nleft=count;
            ssize_t nwrite;
            char *charbuf=(char*) buf;
    
            while(nleft>0)
            {
                    nwrite=write(fd,charbuf,nleft);
                    if(nwrite<0)
                      {
                            if(errno==EINTR)
                               continue;
                            return -1;
                      }
                    else if(nwrite==0)
                           return count-nleft;
                    charbuf +=nwrite;
                    nleft=count-nwrite; 
    
            }
           return count;
    }
    
     ssize_t recv_peek(int sockfd, void *buf, size_t len)
    {
            int ret;
        while(1)
        {
                ret=recv(sockfd,buf,len,MSG_PEEK);
                    if(ret==-1&& errno==EINTR)
                        continue;
                    return ret;
        }
    }
    
     ssize_t readline(int sockfd, void *buf, size_t len)
    {
            ssize_t nleft=len,nread;
            int ret;
            char* bufchar=buf;
            while(1)
            {
                    ret=recv_peek(sockfd,bufchar,len);
                    if(ret<0||ret==0)
                            return ret;
                    nread=ret;
                    int i;
                    for(i=0;i<nread;i++)
                    {
                            if(bufchar[i]=='
    ')
                            {
                                    ret=readn(sockfd,bufchar,i+1);
                                    if(ret!=i+1)
                                            exit(EXIT_FAILURE);
                                    return ret;
                            }
                    }
                    if(nread>nleft)
                            exit(EXIT_FAILURE);
                    nleft-=nread;
                    ret=readn(sockfd,bufchar,nread);
                    if(ret!=nread)
                            exit(EXIT_FAILURE);
                    bufchar+=nread;
    
            }
            return -1;
    
    }
    
    
    int main()
    {
        int sock_fd,new_fd,fd;//sock_fd用于监听,new_fd用于连接
        int maxi;
        struct pollfd client[FD_SETSIZE];//用于存放客户端描述符
        int nready;//检测到的事件数
        struct sockaddr_in srv_addr;//服务器的地址信息
        struct sockaddr_in client_addr;//客户机的地址信息
        int i,size; //地址结构数据的长度
        fd_set rset,allset;     
        char sendbuf[1024],recvbuf[1024];
        memset(sendbuf,0,sizeof(sendbuf));
        memset(recvbuf,0,sizeof(recvbuf));
    
        /*创建套接字*/
        sock_fd=socket(AF_INET,SOCK_STREAM,0);//采用IPv4协议
        if(sock_fd==-1)
        {
            perror("creat socket failed");
            exit(1);
        }
        
        /*服务器地址参数*/
        srv_addr.sin_family=AF_INET;  
        srv_addr.sin_port=htons(3490);
        srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
        bzero(&srv_addr.sin_zero,sizeof(struct sockaddr_in));//bzero位清零函数,将sin_zero清零,sin_zero为填充字段,必须全部为零
        
        int on=1; //表示开启reuseaddr
        if(setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)  //打开地址、端口重用
            perror("setsockopt");
        
        /*绑定地址和端口*/
        if(bind(sock_fd,(struct sockaddr*)&srv_addr,sizeof(struct sockaddr))==-1)
        {
            perror("bind failed");
            exit(1);
        }
        
        /*设置监听模式,等待客户机的监听*/
         if((listen(sock_fd,5))==-1)
        {
            perror("listen failed");
            exit(1);
        }
        
         
        int maxi=0;
        client[0].fd=sock_fd;    //将监听套接字放在数组中
        client[0].events=POOLIN; //感兴趣的事件为数据可读
        for(i=1;i<FD_SETSIZE;i++)
            client[i].fd=-1;    //描述符为-1表示空闲
         
    
        //使用poll实现并发服务器
        while(1)   
        {
            nready=poll(client,maxi+1,-1);  //超时时间为-1,表示阻塞直到检测到事件
            if(nready==-1)
            {
                if(errno==EINTR)     //因为信号中断退出
                    continue;
                perror("select
    ");
            }
            else if(nready==0) //超时
            {
                continue;
            }
            
            if(client[0].revents & POLLIN) //监听套接口产生可读
            {
                size=sizeof(struct sockaddr_in);
                new_fd=accept(sock_fd,(struct sockaddr*)&client_addr,&size);  /*接受连接,采用非阻塞是的模式调用accep*/
                if(new_fd==-1)
                {
                    perror("accept failed");
                //continue;//restart accept when EINTR
                }
            
                    printf("server:got connection from IP= %s prot= %d 
    ",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));//连接成功,打印客户机IP地址和端口号
                /*char *inet_nota(struct sockaddr_in in);
                头文件:
                arpa/inet.h
                Winsock2.h
                参数:
                一个网络上的IP地址
                返回值:
                如果正确,返回一个字符指针,指向一块存储着点分格式IP地址的静态缓冲区(同一线程内共享此内存);错误,返回NULL。
                uint31_t ntohs(uint32_t net32bitvalue);
                头文件:
                #include<netinet/in.h>
                把net32bitvalue有网络字节序转换为主机字节序。
                */
                        if(send(new_fd,"Hello client,I am 192.168.229.125!
    ",50,0)==-1)  //192.168.229.125为子进程IP,可更改
                            perror("send failed");
                for(i=1;i<FD_SETSIZE;i++)    //检测已连接套接字中是否有套接字产生

    {
    if
    (client[i].fd<0)
                    {
                        client[i].fd=new_fd;         //将描述符保存在某一个空闲的位置
                        break;
                    }
                if(i==FD_SETSIZE)                //没有找到空闲的位置,即描述符个数达到上限
                    perror("too many client");
                if(i>maxi)
                    maxi=i;
                client[i].events=POLLIN;
                if(--nready<=0)         //若检测到的套接口已经处理完,则继续用poll监听
                    continue;
            }
        
            for(i=1;i<=maxi;i++)       
            {
                if((fd=client[i].fd)<0)
                    continue;
                if(client[i].revents & POLLIN)   //连接套接口产生事件
                {
                    memset(recvbuf,0,sizeof(recvbuf));
                    if((n=readline(fd,recvbuf,MAXLINE))==0)
                    {
                        printf("client closed
    ");
                        close(fd);
                        client[i].fd=-1;
                    }                
                    else if(n==-1)
                        perror("readline
    ");
                    else
                    {
                        writen(fd,recvbuf,n);
                        fputs(recvbuf,stdout);
                    }
        
                    if(--nready<=0)
                        break;                    
                }
            }
    
        }
     }
  • 相关阅读:
    temp
    JAVA&nbsp;存储空间 寄存器 堆栈 堆…
    数据类型、变量、数组类
    ubuntu ARP 防御
    详解 JAVA 创建对象 NEW
    Eclipse常见问题集锦
    解决error:2014 Commands out of sync; you can't run this command now
    关于MySql5“data too long for column”问题的探解
    Notepad++编辑Pyhton文件的自动缩进的问题(图文)
    mysql 'latin1' codec can't encode characters的问题
  • 原文地址:https://www.cnblogs.com/wujing-hubei/p/5586876.html
Copyright © 2020-2023  润新知