linux 網路編程【四】 非阻塞通訊poll

來源:互聯網
上載者:User
函數原型

#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);

typedef struct pollfd {
        int fd;                               /* 需要被檢測或選擇的檔案描述符*/
        short events;                   /* 對檔案描述符fd上感興趣的事件 */
        short revents;                  /* 檔案描述符fd上當前實際發生的事件*/
} pollfd_t;

typedef unsigned long   nfds_t;

參數說明:

fds:是一個struct pollfd結構類型的數組,用於存放需要檢測其狀態的Socket描述符;每當調用這個函數之後,系統不會清空這個數組,操作起來比較方便;特別是對於socket串連比較多的情況下,在一定程度上可以提高處理的效率;這一點與select()函數不同,調用select()函數之後,select()函數會清空它所檢測的socket描述符集合,導致每次調用select()之前都必須把socket描述符重新加入到待檢測的集合中;因此,select()函數適合於只檢測一個socket描述符的情況,而poll()函數適合於大量socket描述符的情況;

nfds:nfds_t類型的參數,用於標記數組fds中的結構體元素的總數量;

timeout:是poll函數調用阻塞的時間,單位:毫秒;

傳回值:

>0:數組fds中準備好讀、寫或出錯狀態的那些socket描述符的總數量;

==0:數組fds中沒有任何socket描述符準備好讀、寫,或出錯;此時poll逾時,逾時時間是timeout毫秒;換句話說,如果所檢測的socket描述符上沒有任何事件發生的話,那麼poll()函數會阻塞timeout所指定的毫秒時間長度之後返回,如果timeout==0,那麼poll() 函數立即返回而不阻塞,如果timeout==INFTIM,那麼poll() 函數會一直阻塞下去,直到所檢測的socket描述符上的感興趣的事件發生是才返回,如果感興趣的事件永遠不發生,那麼poll()就會永遠阻塞下去;

-1:  poll函數調用失敗,同時會自動化佈建全域變數errno;

特殊說明

如果待檢測的socket描述符為負值,則對這個描述符的檢測就會被忽略,也就是不會對成員變數events進行檢測,在events上註冊的事件也會被忽略,poll()函數返回的時候,會把成員變數revents設定為0,表示沒有事件發生;

另外,poll() 函數不會受到socket描述符上的O_NDELAY標記和O_NONBLOCK標記的影響和制約,也就是說,不管socket是阻塞的還是非阻塞的,poll()函數都不會收到影響;而select()函數則不同,select()函數會受到O_NDELAY標記和O_NONBLOCK標記的影響,如果socket是阻塞的socket,則調用select()跟不調用select()時的效果是一樣的,socket仍然是阻塞式TCP通訊,相反,如果socket是非阻塞的socket,那麼調用select()時就可以實現非阻塞式TCP通訊;

所以poll() 函數的功能和傳回值的含義與 select() 函數的功能和傳回值的含義是完全一樣的,兩者之間的差別就是內部實現方式不一樣,select()函數基本上可以在所有支援檔案描述符操作的系統平台上運行(如:Linux 、Unix 、Windows、MacOS等),可移植性好,而poll()函數則只有個別的的作業系統提供支援(如:SunOS、Solaris、AIX、HP提供支援,但是Linux不提供支援),可移植性差;

程式碼範例(轉載)伺服器

#include  <unistd.h>#include  <sys/types.h>       /* basic system data types */#include  <sys/socket.h>      /* basic socket definitions */#include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */#include  <arpa/inet.h>       /* inet(3) functions */#include <stdlib.h>#include <errno.h>#include <stdio.h>#include <string.h>#include <poll.h> /* poll function */#include <limits.h>#define MAXLINE 10240#ifndef OPEN_MAX#define OPEN_MAX 40960#endifvoid handle(struct pollfd* clients, int maxClient, int readyClient);int  main(int argc, char **argv){    int servPort = 6888;    int listenq = 1024;    int listenfd, connfd;    struct pollfd clients[OPEN_MAX];    int  maxi;    socklen_t socklen = sizeof(struct sockaddr_in);    struct sockaddr_in cliaddr, servaddr;    char buf[MAXLINE];    int nready;    bzero(&servaddr, socklen);    servaddr.sin_family = AF_INET;    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);    servaddr.sin_port = htons(servPort);    listenfd = socket(AF_INET, SOCK_STREAM, 0);    if (listenfd < 0) {        perror("socket error");    }    int opt = 1;    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {        perror("setsockopt error");    }    if(bind(listenfd, (struct sockaddr *) &servaddr, socklen) == -1) {        perror("bind error");        exit(-1);    }    if (listen(listenfd, listenq) < 0) {        perror("listen error");        }    clients[0].fd = listenfd;    clients[0].events = POLLIN;    int i;    for (i = 1; i< OPEN_MAX; i++)         clients[i].fd = -1;     maxi = listenfd + 1;    printf("pollechoserver startup, listen on port:%d\n", servPort);    printf("max connection is %d\n", OPEN_MAX);    for ( ; ; )  {        nready = poll(clients, maxi + 1, -1);        //printf("nready is %d\n", nready);        if (nready == -1) {            perror("poll error");        }        if (clients[0].revents & POLLIN) {            connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &socklen);            sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);            printf(buf, "");            for (i = 0; i < OPEN_MAX; i++) {                if (clients[i].fd == -1) {                    clients[i].fd = connfd;                    clients[i].events = POLLIN;                    break;                }            }            if (i == OPEN_MAX) {                fprintf(stderr, "too many connection, more than %d\n", OPEN_MAX);                close(connfd);                continue;            }            if (i > maxi)                maxi = i;            --nready;        }        handle(clients, maxi, nready);    }}void handle(struct pollfd* clients, int maxClient, int nready) {    int connfd;    int i, nread;    char buf[MAXLINE];    if (nready == 0)        return;    for (i = 1; i< maxClient; i++) {        connfd = clients[i].fd;        if (connfd == -1)             continue;        if (clients[i].revents & (POLLIN | POLLERR)) {            nread = read(connfd, buf, MAXLINE);//讀取用戶端socket流            if (nread < 0) {                perror("read error");                close(connfd);                clients[i].fd = -1;                continue;            }            if (nread == 0) {                printf("client close the connection");                close(connfd);                clients[i].fd = -1;                continue;            }            write(connfd, buf, nread);//響應用戶端              if (--nready <= 0)//沒有串連需要處理,退出迴圈                break;        }    }}

用戶端

#include  <unistd.h>#include  <sys/types.h>       /* basic system data types */#include  <sys/socket.h>      /* basic socket definitions */#include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */#include  <arpa/inet.h>       /* inet(3) functions */#include <netdb.h> /*gethostbyname function */#include <stdlib.h>#include <errno.h>#include <stdio.h>#include <string.h>#define MAXLINE 1024void handle(int connfd);int main(int argc, char **argv){    char * servInetAddr = "127.0.0.1";    int servPort = 6888;    char buf[MAXLINE];    int connfd;    struct sockaddr_in servaddr;    if (argc == 2) {        servInetAddr = argv[1];    }    if (argc == 3) {        servInetAddr = argv[1];        servPort = atoi(argv[2]);    }    if (argc > 3) {        printf("usage: echoclient <IPaddress> <Port>\n");        return -1;    }    connfd = socket(AF_INET, SOCK_STREAM, 0);    bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(servPort);    inet_pton(AF_INET, servInetAddr, &servaddr.sin_addr);    if (connect(connfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {        perror("connect error");        return -1;    }    printf("welcome to echoclient\n");    handle(connfd);     /* do it all */    close(connfd);    printf("exit\n");    exit(0);}void handle(int sockfd){    char sendline[MAXLINE], recvline[MAXLINE];    int n;    for (;;) {        if (fgets(sendline, MAXLINE, stdin) == NULL) {            break;//read eof        }        /*        //也可以不用標準庫的緩衝流,直接使用系統函數無快取作業        if (read(STDIN_FILENO, sendline, MAXLINE) == 0) {            break;//read eof        }        */        n = write(sockfd, sendline, strlen(sendline));        n = read(sockfd, recvline, MAXLINE);        if (n == 0) {            printf("echoclient: server terminated prematurely\n");            break;        }        write(STDOUT_FILENO, recvline, n);        //如果用標準庫的緩衝流輸出有時會出現問題        //fputs(recvline, stdout);    }}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.