国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Linux|Centos|Ubuntu|系統進程|Fedora|注冊表|Bios|Solaris|Windows7|Windows10|Windows11|windows server|

服務器之家 - 服務器系統 - Linux - IO多路復用之poll全面總結(必看篇)

IO多路復用之poll全面總結(必看篇)

2021-12-13 20:59Linux教程網 Linux

下面小編就為大家帶來一篇IO多路復用之poll全面總結(必看篇)。小編覺得挺不錯的。現在就分享給大家。也給大家做個參考。一起跟隨小編過來看看吧

1、基本知識

poll的機制與select類似,與select在本質上沒有多大差別,管理多個描述符也是進行輪詢,根據描述符的狀態進行處理,但是poll沒有最大文件描述符數量的限制。poll和select同樣存在一個缺點就是,包含大量文件描述符的數組被整體復制于用戶態和內核的地址空間之間,而不論這些文件描述符是否就緒,它的開銷隨著文件描述符數量的增加而線性增大。

2、poll函數

函數格式如下所示:

# include <poll.h>
int poll ( struct pollfd * fds, unsigned int nfds, int timeout);

pollfd結構體定義如下:

?
1
2
3
4
5
6
struct pollfd {
 
int fd;     /* 文件描述符 */
short events;     /* 等待的事件 */
short revents;    /* 實際發生了的事件 */
} ;

 

每一個pollfd結構體指定了一個被監視的文件描述符,可以傳遞多個結構體,指示poll()監視多個文件描述符。每個結構體的events域是監視該文件描述符的事件掩碼,由用戶來設置這個域。revents域是文件描述符的操作結果事件掩碼,內核在調用返回時設置這個域。events域中請求的任何事件都可能在revents域中返回。合法的事件如下:

pollin 有數據可讀。

pollrdnorm   有普通數據可讀。

pollrdband  有優先數據可讀。

pollpri 有緊迫數據可讀。

pollout      寫數據不會導致阻塞。

pollwrnorm   寫普通數據不會導致阻塞。

pollwrband    寫優先數據不會導致阻塞。

pollmsgsigpoll 消息可用。

此外,revents域中還可能返回下列事件:

poller   指定的文件描述符發生錯誤。

pollhup 指定的文件描述符掛起事件。

pollnval指定的文件描述符非法。

這些事件在events域中無意義,因為它們在合適的時候總是會從revents中返回。

使用poll()和select()不一樣,你不需要顯式地請求異常情況報告。

pollin | pollpri等價于select()的讀事件,pollout |pollwrband等價于select()的寫事件。pollin等價于pollrdnorm |pollrdband,而pollout則等價于pollwrnorm。例如,要同時監視一個文件描述符是否可讀和可寫,我們可以設置 events為pollin |pollout。在poll返回時,我們可以檢查revents中的標志,對應于文件描述符請求的events結構體。如果pollin事件被設置,則文件描述符可以被讀取而不阻塞。如果pollout被設置,則文件描述符可以寫入而不導致阻塞。這些標志并不是互斥的:它們可能被同時設置,表示這個文件描述符的讀取和寫入操作都會正常返回而不阻塞。

timeout參數指定等待的毫秒數,無論i/o是否準備好,poll都會返回。timeout指定為負數值表示無限超時,使poll()一直掛起直到一個指定事件發生;timeout為0指示poll調用立即返回并列出準備好i/o的文件描述符,但并不等待其它的事件。這種情況下,poll()就像它的名字那樣,一旦選舉出來,立即返回。

返回值和錯誤代碼

成功時,poll()返回結構體中revents域不為0的文件描述符個數;如果在超時前沒有任何事件發生,poll()返回0;失敗時,poll()返回-1,并設置errno為下列值之一:
ebadf       一個或多個結構體中指定的文件描述符無效。

efaultfds 指針指向的地址超出進程的地址空間。

eintr  請求的事件之前產生一個信號,調用可以重新發起。

einvalnfds參數超出plimit_nofile值。

enomem     可用內存不足,無法完成請求。

3、測出程序

編寫一個echo server程序,功能是客戶端向服務器發送信息,服務器接收輸出并原樣發送回給客戶端,客戶端接收到輸出到終端。

服務器端程序如下:

?
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
 
#include <netinet/in.h>
#include <sys/socket.h>
#include <poll.h>
#include <unistd.h>
#include <sys/types.h>
 
#define ipaddress  "127.0.0.1"
#define port    8787
#define maxline   1024
#define listenq   5
#define open_max  1000
#define inftim   -1
 
//函數聲明
//創建套接字并進行綁定
static int socket_bind(const char* ip,int port);
//io多路復用poll
static void do_poll(int listenfd);
//處理多個連接
static void handle_connection(struct pollfd *connfds,int num);
 
int main(int argc,char *argv[])
{
  int listenfd,connfd,sockfd;
  struct sockaddr_in cliaddr;
  socklen_t cliaddrlen;
  listenfd = socket_bind(ipaddress,port);
  listen(listenfd,listenq);
  do_poll(listenfd);
  return 0;
}
 
static int socket_bind(const char* ip,int port)
{
  int listenfd;
  struct sockaddr_in servaddr;
  listenfd = socket(af_inet,sock_stream,0);
  if (listenfd == -1)
  {
    perror("socket error:");
    exit(1);
  }
  bzero(&servaddr,sizeof(servaddr));
  servaddr.sin_family = af_inet;
  inet_pton(af_inet,ip,&servaddr.sin_addr);
  servaddr.sin_port = htons(port);
  if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1)
  {
    perror("bind error: ");
    exit(1);
  }
  return listenfd;
}
 
static void do_poll(int listenfd)
{
  int connfd,sockfd;
  struct sockaddr_in cliaddr;
  socklen_t cliaddrlen;
  struct pollfd clientfds[open_max];
  int maxi;
  int i;
  int nready;
  //添加監聽描述符
  clientfds[0].fd = listenfd;
  clientfds[0].events = pollin;
  //初始化客戶連接描述符
  for (i = 1;i < open_max;i++)
    clientfds[i].fd = -1;
  maxi = 0;
  //循環處理
  for ( ; ; )
  {
    //獲取可用描述符的個數
    nready = poll(clientfds,maxi+1,inftim);
    if (nready == -1)
    {
      perror("poll error:");
      exit(1);
    }
    //測試監聽描述符是否準備好
    if (clientfds[0].revents & pollin)
    {
      cliaddrlen = sizeof(cliaddr);
      //接受新的連接
      if ((connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen)) == -1)
      {
        if (errno == eintr)
          continue;
        else
        {
          perror("accept error:");
          exit(1);
        }
      }
      fprintf(stdout,"accept a new client: %s:%d\n", inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);
      //將新的連接描述符添加到數組中
      for (i = 1;i < open_max;i++)
      {
        if (clientfds[i].fd < 0)
        {
          clientfds[i].fd = connfd;
          break;
        }
      }
      if (i == open_max)
      {
        fprintf(stderr,"too many clients.\n");
        exit(1);
      }
      //將新的描述符添加到讀描述符集合中
      clientfds[i].events = pollin;
      //記錄客戶連接套接字的個數
      maxi = (i > maxi ? i : maxi);
      if (--nready <= 0)
        continue;
    }
    //處理客戶連接
    handle_connection(clientfds,maxi);
  }
}
 
static void handle_connection(struct pollfd *connfds,int num)
{
  int i,n;
  char buf[maxline];
  memset(buf,0,maxline);
  for (i = 1;i <= num;i++)
  {
    if (connfds[i].fd < 0)
      continue;
    //測試客戶描述符是否準備好
    if (connfds[i].revents & pollin)
    {
      //接收客戶端發送的信息
      n = read(connfds[i].fd,buf,maxline);
      if (n == 0)
      {
        close(connfds[i].fd);
        connfds[i].fd = -1;
        continue;
      }
      // printf("read msg is: ");
      write(stdout_fileno,buf,n);
      //向客戶端發送buf
      write(connfds[i].fd,buf,n);
    }
  }
}

客戶端代碼如下所示:

?
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
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <poll.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
 
#define maxline   1024
#define ipaddress  "127.0.0.1"
#define serv_port  8787
 
#define max(a,b) (a > b) ? a : b
 
static void handle_connection(int sockfd);
 
int main(int argc,char *argv[])
{
  int         sockfd;
  struct sockaddr_in servaddr;
  sockfd = socket(af_inet,sock_stream,0);
  bzero(&servaddr,sizeof(servaddr));
  servaddr.sin_family = af_inet;
  servaddr.sin_port = htons(serv_port);
  inet_pton(af_inet,ipaddress,&servaddr.sin_addr);
  connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
  //處理連接描述符
  handle_connection(sockfd);
  return 0;
}
 
static void handle_connection(int sockfd)
{
  char  sendline[maxline],recvline[maxline];
  int   maxfdp,stdineof;
  struct pollfd pfds[2];
  int n;
  //添加連接描述符
  pfds[0].fd = sockfd;
  pfds[0].events = pollin;
  //添加標準輸入描述符
  pfds[1].fd = stdin_fileno;
  pfds[1].events = pollin;
  for (; ;)
  {
    poll(pfds,2,-1);
    if (pfds[0].revents & pollin)
    {
      n = read(sockfd,recvline,maxline);
      if (n == 0)
      {
          fprintf(stderr,"client: server is closed.\n");
          close(sockfd);
      }
      write(stdout_fileno,recvline,n);
    }
    //測試標準輸入是否準備好
    if (pfds[1].revents & pollin)
    {
      n = read(stdin_fileno,sendline,maxline);
      if (n == 0)
      {
        shutdown(sockfd,shut_wr);
    continue;
      }
      write(sockfd,sendline,n);
    }
  }
}

4、程序測試結果

IO多路復用之poll全面總結(必看篇)

IO多路復用之poll全面總結(必看篇)

IO多路復用之poll全面總結(必看篇)

以上就是小編為大家帶來的io多路復用之poll全面總結(必看篇)全部內容了,希望大家多多支持服務器之家~

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成人免费一区二区三区视频软件 | 亚洲爽爽 | 精品天堂| 亚洲精品在线视频 | a级片在线观看 | 午夜精品成人一区二区 | 久久免费99精品久久久久久 | 日韩精品一区二区三区 | 精品久久久久久亚洲精品 | 狠狠久 | 精品国产视频 | 日韩在线视频一区 | 一级毛片免费看 | 亚洲成人三级 | 欧美成人a | 91久久精品日日躁夜夜躁国产 | 亚洲综合在线播放 | 中文字幕精品一区二区三区精品 | 午夜精品一区二区三区在线播放 | 秋霞特色aa大片 | 国产欧美日韩在线观看 | 999在线观看视频 | 青青草视频在线免费观看 | 91在线免费网站 | 久久久久久高清 | 国产欧美日韩综合精品一区二区 | 一区免费看 | 91精品国产日韩91久久久久久 | 欧美成人一区二区三区 | 中文字幕在线观看一区二区三区 | 中文字幕日韩视频 | 日本天天色 | 亚洲久草| 国产日韩欧美在线 | 成人av播放 | 国产中文一区 | 亚洲情视频 | 久久精品成人免费视频 | 国产成人a亚洲精品 | 日韩综合在线 | 久久人人爽人人爽人人片亚洲 |