• poll


     ■ 函数说明


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

    The set of file descriptors to be monitored is specified in the fds argument, which is an array of structures of the following form:

    struct pollfd {
    int fd; /* file descriptor */
    short events; /* requested events */
    short revents; /* returned events */
    };

    The caller should specify the number of items in the fds array in nfds.

    The timeout argument specifies the number of milliseconds that poll() should block waiting for a file descriptor to become ready. The call will
    block until either:

    * a file descriptor becomes ready;

    * the call is interrupted by a signal handler; or

    * the timeout expires.

    RETURN VALUE
    On success, a positive number is returned; this is the number of structures which have nonzero revents fields (in other words, those descriptors with
    events or errors reported). A value of 0 indicates that the call timed out and no file descriptors were ready. On error, -1 is returned, and errno
    is set appropriately.

    ▶ struct pollfd

    The field fd contains a file descriptor for an open file. If this field is negative, then the corresponding events field is ignored and the revents
    field returns zero. (This provides an easy way of ignoring a file descriptor for a single poll() call: simply negate the fd field. Note, however,
    that this technique can't be used to ignore file descriptor 0.)

    The field events is an input parameter, a bit mask specifying the events the application is interested in for the file descriptor fd. This field may
    be specified as zero, in which case the only events that can be returned in revents are POLLHUP, POLLERR, and POLLNVAL (see below).

    The field revents is an output parameter, filled by the kernel with the events that actually occurred. The bits returned in revents can include any
    of those specified in events, or one of the values POLLERR, POLLHUP, or POLLNVAL. (These three bits are meaningless in the events field, and will be
    set in the revents field whenever the corresponding condition is true.)


    ▶ events and revents

    POLLIN There is data to read.

    POLLPRI
    There is urgent data to read (e.g., out-of-band data on TCP socket; pseudoterminal master in packet mode has seen state change in
    slave).

    POLLOUT
    Writing is now possible, though a write larger that the available space in a socket or pipe will still block (unless O_NONBLOCK is
    set).

    POLLRDHUP (since Linux 2.6.17)
    Stream socket peer closed connection, or shut down writing half of connection. The _GNU_SOURCE feature test macro must be defined
    (before including any header files) in order to obtain this definition.

    POLLERR
    Error condition (only returned in revents; ignored in events).

    POLLHUP
    Hang up (only returned in revents; ignored in events). Note that when reading from a channel such as a pipe or a stream socket, this
    event merely indicates that the peer closed its end of the channel. Subsequent reads from the channel will return 0 (end of file) only
    after all outstanding data in the channel has been consumed.

    POLLNVAL
    Invalid request: fd not open (only returned in revents; ignored in events).

    When compiling with _XOPEN_SOURCE defined, one also has the following, which convey no further information beyond the bits listed above:

    POLLRDNORM
    Equivalent to POLLIN.

    POLLRDBAND
    Priority band data can be read (generally unused on Linux).

    POLLWRNORM
    Equivalent to POLLOUT.

    POLLWRBAND
    Priority data may be written.

     

    ■  poll使用步骤

    #include<poll.h>

    #define IN_FILES 2

    struct pollfd fds[IN_FILES];

    fds[0].fd = fd1;
    fds[0].events = POLLIN;
    fds[1].fd = fd2;
    fds[1].events = POLLIN;

    int result;
    result = poll(fds, IN_FILES, 3000);
    if (result == 0) {
    printf("Poll timeout ");
    } else if (result > 0) {
    printf("Poll successfully ");
    } else {
    printf("Poll error ");
    }

    if (fds[0].revents == POLLIN)
    {
    fds[0].revents &= ~POLLIN;
    //do callback for fd1
    }

    if (fds[1].revents == POLLIN)
    {
    fds[1].revents &= ~POLLIN;
    //do callback for fd2
    }

     注意:

    使用者关注fd1的POLLIN events   fds[0].fd = fd1; fds[0].events = POLLIN;

    poll之后,用户关注是fds[0].revents

            使用的是fds[0]的不同参数。

    ■  例子程序


    server.c

    //server.c
    #include<stdio.h>  
    #include<stdlib.h>  
    #include<string.h>  
    #include<errno.h>  
    #include<sys/types.h>  
    #include<sys/socket.h>  
    #include<netinet/in.h>  
    #include<poll.h>
    #include <unistd.h>
    
    #define DEFAULT_PORT 8000  
    #define MAXLINE 4096  
    #define IN_FILES 1//我们这里poll机制只监听一个文件描述符
    
    void socket_accept(int socket_fd) {
        int connect_fd;  
        char    buff[MAXLINE];  
        //阻塞直到有客户端连接,不然浪费CPU资源,但是显然这里通过poll机制是有可读的信息才会进入本函数,因此应该是不会阻塞的。
        if ((connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1) { 
            printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
        }
    
        int n = recv(connect_fd, buff, MAXLINE, 0);
        buff[n] = '';
        printf("recv msg from client: %s
    ", buff);
    
        if (send(connect_fd, "Hello,you are connected!
    ", 26, 0) == -1) {
            perror("send error");
        }
    
        close(connect_fd);
    }
    
    int main(int argc, char** argv)  
    {  
        int    socket_fd, connect_fd;  
        struct sockaddr_in     servaddr;  
        struct pollfd fds[IN_FILES];
    
        //初始化Socket  
        if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  
            printf("create socket error: %s(errno: %d)
    ",strerror(errno),errno);  
            exit(0);  
        }
    
        //初始化  
        memset(&servaddr, 0, sizeof(servaddr));  
        servaddr.sin_family = AF_INET;  
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。  
        servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT  
      
        //将本地地址绑定到所创建的套接字上  
        if (bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) {  
            printf("bind socket error: %s(errno: %d)
    ",strerror(errno),errno);  
            exit(0);  
        }  
    
        //开始监听是否有客户端连接  
        if (listen(socket_fd, 10) == -1) {  
            printf("listen socket error: %s(errno: %d)
    ",strerror(errno),errno);  
            exit(0);  
        }  
    
    
        fds[0].fd = socket_fd;
        fds[0].events = POLLIN;
        int result;
        while(1){
            printf("begin to poll()
    ");
             printf("fds[0].fd = %d fds[0].events = %d fds[0].revents = %d POLLOUT = %d
    ",fds[0].fd , fds[0].events,
             fds[0].revents, POLLOUT);
           result = poll(fds, IN_FILES, -1);  //It may block with timeout
            if (result == 0) {
                printf("Poll timeout
    ");
            } else if (result > 0) {
                printf("Poll successfully
    ");
            } else {
                printf("Poll error
    ");
            } 
    
            if (fds[0].revents == POLLIN){ 
                fds[0].revents &= ~POLLIN;
                printf("===receive a connetction====
    ");
                socket_accept(socket_fd);
            }
    
            printf("do something else
    ");
            sleep(1);
            printf("do something else end
    ");
        }
    
        close(socket_fd);  
    }

    client.c

    //client.c
    // run$ ./client.o 127.0.0.1
    #include<stdio.h>  
    #include<stdlib.h>  
    #include<string.h>  
    #include<errno.h>  
    #include<sys/types.h>  
    #include<sys/socket.h>  
    #include<netinet/in.h>  
    #include <unistd.h>
    #include <arpa/inet.h>
      
    #define MAXLINE 4096  
      
    int main(int argc, char** argv)  
    {  
        int    sockfd, n,rec_len;  
        char    recvline[4096], sendline[4096];  
        char    buf[MAXLINE];  
        struct sockaddr_in    servaddr;  
      
      
        if (argc != 2) {  
            printf("usage: ./client <ipaddress>
    ");  
            exit(0);  
        }    
      
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {  
            printf("create socket error: %s(errno: %d)
    ", strerror(errno),errno);  
            exit(0);  
        }  
      
        memset(&servaddr, 0, sizeof(servaddr));  
        servaddr.sin_family = AF_INET;  
        servaddr.sin_port = htons(8000);  
        if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {  
            printf("inet_pton error for %s
    ",argv[1]);  
            exit(0);  
        }  
      
        if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {  
            printf("connect error: %s(errno: %d)
    ",strerror(errno),errno);  
            exit(0);  
        }  
      
        printf("send msg to server: 
    ");  
        fgets(sendline, 4096, stdin);  
        if (send(sockfd, sendline, strlen(sendline), 0) < 0) {  
            printf("send msg error: %s(errno: %d)
    ", strerror(errno), errno);  
            exit(0);  
        }
    
        if ((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) {  
           perror("recv error");  
           exit(1);  
        }
    
        buf[rec_len]  = '';  
        printf("Received : %s ",buf);  
        close(sockfd);  
        exit(0);  
    }

    Makefile

    #https://www.cnblogs.com/muhe221/articles/4487763.html
    all : 
        gcc server.c -o server
        gcc client.c -o client
    
    clean:
        rm -f server client
    
    .PHONY:all clean

    运行:

    ./server

    ./client 127.0.0.1

  • 相关阅读:
    ArrayBlockingQueue的使用案例:
    mysql中insert into select from的使用
    springboot项目中进行并发测试
    springboot自己实现mysql主从数据切换机制
    启动zuul时候报错:The bean 'proxyRequestHelper', defined in class path resource [org/springframework/cloud/netflix/zuul
    redis集群
    postman创建mocker Server
    springcloud应用思考
    vue进行路由拼图的使用案例
    【适合N卡独显电脑的环境配置】Tensorflow教程-Windows 10下安装tensorflow 1.5.0 GPU with Anaconda
  • 原文地址:https://www.cnblogs.com/renhl/p/13057425.html
Copyright © 2020-2023  润新知