I/O多路轉接之poll 函式
poll
一、poll()函式:
這個函式是某些Unix系統提供的用於執行與select()函式同等功能的函式,自認為poll和select大同小異,下面是這個函式的宣告:
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
引數:
1.第一個引數:一個結構陣列,struct pollfd:
fds:是一個struct pollfd結構型別的陣列,每個陣列元素都是一個pollfd結構,用於指定測試某個給定描述字fd的條件。存放需要檢測其狀態的Socket描述符;每當呼叫這個函式之後,系統不會清空這個陣列,操作起來比較方便;
結構如下:
struct pollfd{ int fd; //檔案描述符 short events; //請求的事件 short revents; //返回的事件 };
events和revents是通過對代表各種事件的標誌進行邏輯或運算構建而成的。events包括要監視的事件(就是我需要關注的時間,是讀?是寫?還是出錯?),poll用已經發生的事件填充revents。poll函式通過在revents中設定標誌肌膚POLLHUP、POLLERR和POLLNVAL來反映相關條件的存在。不需要在events中對於這些標誌符相關的位元位進行設定。如果fd小於0,
則events欄位被忽略,而revents被置為0.標準中沒有說明如何處理檔案結束。檔案結束可以通過revents的識別符號POLLHUN或返回0位元組的常規讀操作來傳達。即使POLLIN或POLLRDNORM指出還有資料要讀,POLLHUP也可能會被設定。因此,應該在錯誤檢驗之前處理正常的讀操作。
poll函式的事件標誌符值:
常量 | 說明 |
POLLIN | 普通或優先順序帶資料可讀 |
POLLRDNORM | 普通資料可讀 |
POLLRDBAND | 優先順序帶資料可讀 |
POLLPRI | 高優先順序資料可讀 |
POLLOUT | 普通資料可寫 |
POLLWRNORM | 普通資料可寫 |
POLLWRBAND | 優先順序帶資料可寫 |
POLLERR | 發生錯誤 |
POLLHUP | 發生掛起 |
POLLNVAL | 描述字不是一個開啟的檔案 |
注意:
1)後三個只能作為描述字的返回結果儲存在revents中,而不能作為測試條件用於events中。
2)第二個引數nfds:要監視的描述符的數目。
3)最後一個引數timeout:是一個用毫秒表示的時間,是指定poll在返回前沒有接收事件時應該等待的時間。如果 它的值為-1,poll就永遠都不會超時。如果整數值為32個位元,那麼最大的超時週期大約是30分鐘。
timeout值 | 說明 |
INFTIM | 永遠等待 |
0 | 立即返回,不阻塞程序 |
>0 | 等待指定數目的毫秒數 |
如果是對一個描述符上的多個事件感興趣的話,可以把這些常量標記之間進行按位或運算就可以了;
比如:
對socket描述符fd上的讀、寫、異常事件感興趣,就可以這樣做:
struct pollfd fds;
fds[index].events=POLLIN | POLLOUT | POLLERR;
當 poll()函式返回時,要判斷所檢測的socket描述符上發生的事件,可以這樣做:
struct pollfd fds;
//檢測可讀TCP連線請求:
if((fds[nIndex].revents & POLLIN) == POLLIN)
{
<span style="white-space:pre"> </span>//接收資料,呼叫accept()接收連線請求
}
//檢測可寫:
if((fds[nIndex].revents & POLLOUT) == POLLOUT)
{
<span style="white-space:pre"> </span>//傳送資料
}
//檢測異常:
if((fds[nIndex].revents & POLLERR) == POLLERR)
{
<span style="white-space:pre"> </span>//異常處理
}
二、例項TCP伺服器的伺服器程式
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <poll.h> //for poll
#define LISTENQ 1024
#define MAXLINE 1024
#define OPEN_MAX 50000
#ifndef INFTIM
#define INFTIM -1
#endif
int start_up(char* ip,int port) //建立一個套接字,繫結,檢測伺服器
{
//sock
//1.建立套接字
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("sock");
exit(0);
}
//2.填充本地 sockaddr_in 結構體(設定本地的IP地址和埠)
struct sockaddr_in local;
local.sin_port=htons(port);
local.sin_family=AF_INET;
local.sin_addr.s_addr=inet_addr(ip);
//3.bind()繫結
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
exit(1);
}
//4.listen()監聽 檢測伺服器
if(listen(sock,back_log)<0)
{
perror("sock");
exit(1);
}
return sock; //這樣的套接字返回
}
int main(int argc, char *argv[])
{
int i, maxi, connfd, sockfd;
int nready;
ssize_t n;
socklen_t clilen;
struct sockaddr_in servaddr;
socklen_t len=sizeof(servaddr);
char buf[BUFSIZ];
struct pollfd client[OPEN_MAX]; // 用於poll函式第一個引數的陣列,存放每次的檔案描述符個數
if( argc != 3 )
{
printf("Please input %s <hostname>\n", argv[0]);
exit(2);
}
int listenfd=start_up(argv[1],argv[2]); //建立一個綁定了本地 ip 和埠號的套接字描述符
client[0].fd = listenfd; //將陣列中的第一個元素設定成監聽描述字
client[0].events = POLLIN; //將測試條件設定成普通或優先順序帶資料可讀(感興趣的事件讀、寫、出錯),此處書中為POLLRDNORM,*/
client[0].revents = 0; //真正發生的事件
for(i = 1;i < OPEN_MAX; ++i) //陣列中的其它元素將暫時設定成不可用
{
client[i].fd = -1;
}
maxi = 0;
while(1)
{
nready = poll(client, maxi+1,INFTIM); //將程序阻塞在poll上
if( client[0].revents & POLLIN) //先測試監聽描述字
{
connfd = accept(listenfd,(struct sockaddr*)&servaddr, &clilen);
for(i = 1; i < OPEN_MAX; ++i)
{
if( client[i].fd < 0 )
{
client[i].fd = connfd; //將新連線加入到測試陣列中
client[i].events = POLLIN; //POLLRDNORM; 測試條件普通資料可讀
break;
}
if( i == OPEN_MAX )
{
printf("too many clients"); //連線的客戶端太多了,都達到最大值了
exit(1);
}
if( i > maxi )
maxi = i; //maxi記錄的是陣列元素的個數
if( --nready <= 0 )
continue; //如果沒有可讀的描述符了,就重新監聽連線
}
}
for(i = 1; i <= maxi; i++) //測試除監聽描述字以後的其它連線描述字
{
if( (sockfd = client[i].fd) < 0) //如果當前描述字不可用,就測試下一個
continue;
if(client[i].revents & (POLLIN | POLLERR))//如果當前描述字返回的是普通資料可讀或出錯條件
{
if( (n = read(sockfd, buf, MAXLINE)) < 0) //從套介面中讀資料
{
if( errno == ECONNRESET) //如果連線斷開,就關閉連線,並設當前描述符不可用
{
close(sockfd);
client[i].fd = -1;
}
else
perror("read error");
}
else if(n == 0) //如果資料讀取完畢,關閉連線,設定當前描述符不可用
{
close(sockfd);
client[i].fd = -1;
}
else
write(sockfd, buf, n); //列印資料
if(--nready <= 0)
break;
}
}
}
exit(0);
}
賜教!相關推薦
I/O多路轉接之poll 函式
poll 一、poll()函式: 這個函式是某些Unix系統提供的用於執行與select()函式同等功能的函式,自認為poll和select大同小異,下面是這個函式的宣告: #include <poll.h> int poll(struct pollfd *
I/O多路轉接之select、poll、epoll
I/O多路轉接之select 系統提供select函式來實現多路複用輸入/輸出模型。select系統呼叫是用來讓我們的程式監視多個檔案控制代碼的狀態變化的。程式會停在select這裡等待,直到被監視的檔案控制代碼有一個或多個發生了狀態改變。關於檔案
I/O多路轉接之select伺服器
(1)每次調⽤用select,都需要把fd集合從⽤使用者態拷貝到核心態,這個開銷在fd很多時會很⼤大 (2)同時每次調⽤用select都需要在核心遍歷傳遞進來的所有fd,這個開銷在fd很多時也很⼤大 (3)select⽀支援的⽂檔案描述符數量太⼩小了,預設是10
I/O多路轉接之select
在完成I/O操作時,程式中完成真正I/O的時間可能只有少的一部分,而大部分時間都處於一個等的時間。比如,此時需要從一個套接字中讀取資料read(socket, buf, BUFSIZE); 這個操作可能會一直阻塞,直到有資料從網路的另一端傳送過來。等的時間過於長,這是I/
I/O多路轉接——select、poll 和 epoll
一、select 1. select() 函式 select系統呼叫是用來讓我們的程式監視多個檔案描述符的狀態變化的; 程式會停在select這裡等待,直到被監視的檔案描述符有一個或多個發生了狀態改變。 select函
I/O多路轉接-epoll
原本 oid com pue tdi 數據 錯誤 系統 val By francis_hao Aug 5,2017 APUE講多路轉接的章節介紹了select、pselect和poll函數。而epoll是linux內核在2.5.44引入的。在glibc 2.3.2
select函數與I/O多路轉接
error strong pan 實現 tail 問題 exce 準備就緒 這樣的 select函數與I/O多路轉接 相作大家都寫過讀寫IO操作的代碼,例如從socket中讀取數據可以使用如下的代碼: while( (n = read(socketfd, buf, BU
I/O多路複用——poll
上一篇我們說了關於select的相關資訊,我們可以看到select是有弊端的,所以為了解決select的弊端,UNIX又在後期提出了poll。 select的弊端這裡就不多說了,上一篇部落格有提及。 poll poll和select類似,不過在一些
迴圈伺服器,併發伺服器模型以及I/O多路轉接模型
一、基於TCP/IP協議的基本迴圈伺服器 tcp_server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h&
網路程式設計-多路轉接之poll與epoll模型
首先,還是需要理解io過程:io過程總體來看分兩步,第一步就是等,第二步才是資料搬遷。而如果要想提高io的效能與效率,就要減少等的比重。 可以假想一個場景: 你去釣魚,但是你只有一個魚竿。你的同伴也和你一起去釣魚,但是他帶了100個魚竿。假設每條魚上
I/O多路復用之select,poll,epoll簡介
重新 才會 增長 文件描述 brush 重新編譯 () 情況 包含 一、select 1.起源 select最早於1983年出現在4.2BSD中(BSD是早期的UNIX版本的分支)。 它通過一個select()系統調用來監視多個文件描述符的數組,當select()返回後,該
I/O多路複用之select、poll、epoll
很早之前有寫過篇IO多路複用的文章:https://www.cnblogs.com/klcf0220/archive/2013/05/14/3077003.html 參考連結:https://segmentfault.com/a/1190000003063859 select,poll,epoll都是IO多路
I/O多路復用之select、poll、epoll
不同 file roc 測試 max 復用 隊列 最大 而且 很早之前有寫過篇IO多路復用的文章:https://www.cnblogs.com/klcf0220/archive/2013/05/14/3077003.html參考鏈接:https://segmentfaul
unix網絡編程——I/O多路復用之epoll
得到 是否 再次 專用 空間 line 正常 時間服務 struct 1. 基本概念 當程序進行IO時,如果數據尚未準備好,那麽IO將處於阻塞狀態。當某個進程有多個打開的文件,比如socket,那麽其後的所有準備好讀寫的文件將受到阻塞的影響而不能操作。不借助線程,單一進
Linux網路程式設計---I/O多路複用之select
1.I/O多路複用(IO multiplexing) 我們之前講了I/O多路複用和其他I/O的區別,在這裡,我們再具體討論下I/O多路複用是怎麼工作? I/O 多路複用技術就是為了解決程序或執行緒阻塞到某個 I/O 系統呼叫而出現的技術,使程序不阻塞於某個特定的 I/O 系統呼叫。
嵌入式Linux網路程式設計,I/O多路複用,poll()示例,poll()客戶端,poll()伺服器,單鏈表
文章目錄 1,IO複用poll()示例 1.1,poll()---net.h 1.2,poll()---client.c 1.3,poll()---sever.c 1.4,poll()---linklist.h 1.5,p
嵌入式Linux網路程式設計,I/O多路複用,阻塞I/O模式,非阻塞I/O模式fcntl()/ioctl(),多路複用I/O select()/pselect()/poll(),訊號驅動I/O
文章目錄 1,I/O模型 2,阻塞I/O 模式 2.1,讀阻塞(以read函式為例) 2.2,寫阻塞 3,非阻塞模式I/O 3.1,非阻塞模式的實現(fcntl()函式、ioctl() 函式)
IO基礎入門之I/O多路複用技術
在I/O程式設計過程中,當需要同時處理多個客戶端接入請求時,可以利用多執行緒或者I/O多路複用技術進行處理。I/O多路複用技術通過把多個I/O的阻塞複用到同一個select的阻塞上,從而使得系統在單執行緒的情況下可以同時處理多個客戶端請求。與傳統的多執行緒/多程序模型比,I
淺談網路I/O多路複用模型 select & poll & epoll
我們首先需要知道select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,
I/O多路複用之 epoll 系統呼叫
I/O多路複用除了之前我們提到的select和poll外,epoll 也可以檢查多個檔案描述符的就緒狀態,以達到I/O多路複用的目的。 epoll 系統呼叫是 Linux 系統專有的,在 Linux 核心 2.6 版本新增,epoll 的主要優點有: 當檢