日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

unix下網(wǎng)絡編程之I/O復用(三)

 看風景D人 2014-01-08

poll函數(shù)

    在上文unix下網(wǎng)絡編程之I/O復用(二)中已經(jīng)介紹了select函數(shù)的相關使用,本文將介紹另一個常用的I/O復用函數(shù)poll。poll提供的功能與select類似,不過在處理流設備時,它能夠提供額外的信息。

poll函數(shù)原型:

1
2
3
#include<poll.h>
   int poll (struct pollfd * fdarray , unsigned long nfds , int timeout);
   //返回:就需描述字的個數(shù),0——超時,-1——出錯

 第一個參數(shù)是指向一個結構數(shù)組第一個元素的指針,每個數(shù)組元素都是一個pollfd結構。如下:

1
2
3
4
5
struct pollfd {
    int fd; //descriptor to check
    short events; //events of interest on fd
`   short revents; //events tha occurred on fd
}

要測試的條件由events成員指定,函數(shù)在相應的revents成語中返回該描述字的狀態(tài)。(每個描述字都有兩個變量,一個為調用值,另一個為返回結果,從而避免使用值-結果參數(shù),這與select函數(shù)是不同的)。下圖列出了用于指定events標志以及測試revents標志的一些常值。

image

上圖需要注意的是,POLLERR,POLLHUP,POLLNVAL是處理錯誤的描述字,因此它們也就不可以出現(xiàn)在input事件中,即events。poll識別三類數(shù)據(jù):普通(normal),優(yōu)先級帶(priority band)和高優(yōu)先級(high priority)。

對TCP和UPD而言,以下條件引起poll返回特定的revents。

1、 All regular TCP data and all UDP data is considered normal.
2、 TCP's out-of-band data (Chapter 24) is considered priority band.
3、 When the read half of a TCP connection is closed (e.g., a FIN is received), this is also considered normal data and a subsequent read operation will return 0.
4、 The presence of an error for a TCP connection can be considered either normal data or an error (POLLERR). In either case, a subsequent read will return –1 with errno set to the appropriate value. This handles conditions such as the receipt of an RST or a timeout.
5、 The availability of a new connection on a listening socket can be considered either normal data or priority data. Most implementations consider this normal data.
6、 The completion of a nonblocking connect is considered to make a socket writable.

                                                                                    ——《unix網(wǎng)絡編程》第三版

參數(shù)nfds,指示結構數(shù)組中元素的個數(shù)。

參數(shù)timeout:

與select中的timeout不同,poll函數(shù)的timeout參數(shù)是一int值,表示poll函數(shù)返回前等待多長時間,它是毫秒級別的。它有三種情況的取值:1、INFTIM(一個負數(shù)值),表示永遠等待,即一直阻塞。2、0,表示立即返回,非阻塞。3、>0,表示正待指定數(shù)目的毫秒數(shù)。

poll函數(shù)的返回值:

當poll發(fā)生錯誤時,poll函數(shù)的返回值-1,若定時器時間到之前沒有任何描述字就緒,則返回0,否則返回就緒描述字的個數(shù),即其revents成員值非0的描述字個數(shù)。

如果我們不再關心某個特定描述字,那么可以把與他對應的pollfd結構的fd成員設置成一個負值。poll函數(shù)將忽略這樣的pollfd結構的events成員,返回時將它的revents成員的值置為0。

 

poll函數(shù)的通信列子:一個簡單的TCP回射服務器程序

pollServer.c:使用select機制的服務器程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <poll.h>
  
/*環(huán)境為ubuntu10.04自帶c環(huán)境,無法自動引入下列宏,所以自己寫在前面了*/
#define INFTIM -1
#define POLLRDNORM  0x040       /* Normal data may be read.  */
#define POLLRDBAND  0x080       /* Priority data may be read.  */
#define POLLWRNORM  0x100       /* Writing now will not block.  */
#define POLLWRBAND  0x200       /* Priority data may be written.  */
  
#define MAXLINE  1024
#define OPEN_MAX  16 //一些系統(tǒng)會定義這些宏
#define SERV_PORT  10001
  
int main()
{
    int i , maxi ,listenfd , connfd , sockfd ;
    int nready;
    int n;
    char buf[MAXLINE];
    socklen_t clilen;
    struct pollfd client[OPEN_MAX];
  
    struct sockaddr_in cliaddr , servaddr;
    listenfd = socket(AF_INET , SOCK_STREAM , 0);
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  
    bind(listenfd , (struct sockaddr *) & servaddr, sizeof(servaddr));
    listen(listenfd,10);
    client[0].fd = listenfd;
    client[0].events = POLLRDNORM;
    for(i=1;i<OPEN_MAX;i++)
    {
        client[i].fd = -1;
    }
    maxi = 0;
  
    for(;;)
    {
        nready = poll(client,maxi+1,INFTIM);
        if (client[0].revents & POLLRDNORM)
        {
            clilen = sizeof(cliaddr);
            connfd = accept(listenfd , (struct sockaddr *)&cliaddr, &clilen);
            for(i=1;i<OPEN_MAX;i++)
            {
                if(client[i].fd<0)
                {
                    client[i].fd = connfd;
                    client[i].events = POLLRDNORM;
                    break;
                }
            }
            if(i==OPEN_MAX)
            {
                printf("too many clients! \n");
            }
            if(i>maxi) maxi = i;
            nready--;
            if(nready<=0) continue;
        }
  
        for(i=1;i<=maxi;i++)
        {
            if(client[i].fd<0) continue;
            sockfd = client[i].fd;
            if(client[i].revents & (POLLRDNORM|POLLERR))
            {
                n = read(client[i].fd,buf,MAXLINE);
                if(n<=0)
                {
                    close(client[i].fd);
                    client[i].fd = -1;
                }
                else
                {
                    buf[n]='\0';
                    printf("Socket %d said : %s\n",sockfd,buf);
                    write(sockfd,buf,n); //Write back to client
                }
                nready--;
                if(nready<=0) break; //no more readable descriptors
            }
        }
    }
    return 0;
}

客戶端程序參考上一篇文章。

總結:

   本文介紹了poll函數(shù)的原型,參數(shù)說明,注意事項以及一個簡單的代碼例子。在unix后續(xù)版本中,加入了epoll函數(shù)I/O復用機制,它在一定條件下更加高效,在以后的文章中,會對epoll機制再進行詳細的描述。之前在學習python的時候,也接觸了select和poll,但是當時了解的比較淺顯,希望通過最近的學習可以對unix下I/O復用有更深入的認識。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多