日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

poll f服务器

發布時間:2024/4/11 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 poll f服务器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
poll優點:
1.poll監聽的文件描述符沒有最大數量的限制

2.poll對于select來說包含了一個pollfd結構,pollfd結構包含了要監視的event和發生的revent,而不像select那樣使用輸入輸出的傳遞方式。所以不需要每次監聽都初始化

poll缺點:
1.數量過大以后其效率也會線性下降。
2.poll和select一樣也是返回就緒事件的個數,需要遍歷文件描述符來判斷是那個事件已經就緒,當數量很大時,開銷也就很大。
3.select和poll都只能工作在低效的LT(水平觸發)模式
4.每次調用poll,都需要把pollfd數組從用戶態拷貝到內核態,這個開銷在fd很多時會很大
5.內核采用輪詢(遍歷pollfd數組)的方式來檢測就緒事件,這個開銷在fd很多時也很大


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

1

1

fds是一個pollfd的結構體數組。


struct pollfd {

? ? ? ? ? ? ? ?int ? fd; ? ? ? ? /* file descriptor */

? ? ? ? ? ? ? ?short events; ? ? /* requested events */

? ? ? ? ? ? ? ?short revents; ? ?/* returned events */

? ? ? ? ? ?};

1

2

3

4

5

6

1

2

3

4

5

6

這就是這個結構體數組每個元素。fd用來記錄對應的文件描述符,events用來表示poll所監聽的事件,這個由用戶來設置。revents用來表示返回的事件。revents是通過內核來進行操作修改。


這里提供了一些合法事件。


事件 說明

POLLIN 普通或優先級帶數據可讀

POLLRDNORM 普通數據可讀

POLLRDBAND 優先級帶數據可讀

POLLPRI 高優先級數據可讀

POLLOUT 普通數據可寫

POLLWRNORM 普通數據可寫

POLLWRBAND 優先級帶數據可寫

POLLERR 發生錯誤

POLLHUP 發生掛起

POLLNVAL 描述字不是一個打開的文件

后面的三個參數在events無意義,只能作為返回結果存儲在revents。


另外,這里需要說的,這些參數如何設置給events,這些宏相當于每一個占用一個比特位,我們可以去想一下位圖,所以,如果我們要進行設置兩個事件,就使用|操作,另外,當我們去查看事件是否發生的時候,這個時候我們可以使用revents&事件,如果事件發生了,那么結果大于1。這就是一個簡單的位運算的,相信你仔細想想就能夠理解。


第二個參數nfds,用來監視的文件描述符的數目。


第三個參數是timeout,用來設置超時時間。


參數 說明

-1 poll將永遠阻塞,等待知道某個時間發生

0 立即返回

大于0的值 設置正常時間值

返回值?

poll返回revents不為0的文件描述符的個數。?

失敗返回-1


總結


poll本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然后查詢每個fd對應的設備狀態,如果設備就緒則在設備等待隊列中加入一項并繼續遍歷,如果遍歷完所有fd后沒有發現就緒設備,則掛起當前進程,直到設備就緒或者主動超時,被喚醒后它又要再次遍歷fd。這個過程經歷了多次無謂的遍歷。


poll使用了events和revents分流的特點,這樣可以使得對關心事件只進行注冊一次。


poll基于鏈表進行存儲,沒有最大連接數的限制,只取決于內存大小。


poll還有一個特點是“水平觸發”,如果報告了fd后,沒有被處理,那么下次poll時會再次報告該fd。


poll的實現機制與select類似,其對應內核中的sys_poll,只不過poll向內核傳遞pollfd數組,然后對pollfd中的每個描述符進行poll,相比處理fdset來說,poll效率更高。poll返回后,需要對pollfd中的每個元素檢查其revents值,來得指事件是否發生。


poll的缺點


1、大量的fd的數組被整體復制于用戶態和內核地址空間之間,而不管這樣是不是有意義。


2、poll依然需要進行輪詢,所消耗的時間太多。


3、水平觸發,效率低



代碼:


[cpp] view plain copy

#include<stdio.h> ?

#include <sys/types.h> ? ? ? ? ?/* See NOTES */ ?

#include <sys/socket.h> ?

#include<stdlib.h> ?

#include<netinet/in.h> ?

#include<poll.h> ?

#include<string.h> ?

??

??

static void usage(const char *str) ?

{ ?

? ? printf("Usage:%s [serv_ip] [serv_port]\n",str); ?

} ?

??

static int startup(const char *ip,int port) ?

{ ?

? ? int sock = socket(AF_INET,SOCK_STREAM,0); ?

? ? if(sock < 0) ?

? ? { ?

? ? ? ? perror("socket"); ?

? ? ? ? exit(1); ?

? ? } ?

??

? ? int opt = 1; ?

? ? setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); ?

??

? ? struct sockaddr_in serv_addr; ?

? ? serv_addr.sin_family = AF_INET; ?

? ? serv_addr.sin_addr.s_addr = inet_addr(ip); ?

? ? serv_addr.sin_port = htons(port); ?

??

? ? int ret ?= bind(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)); ?

? ? if(ret < 0) ?

? ? { ?

? ? ? ? perror("bind"); ?

? ? ? ? exit(2); ?

? ? } ?

??

? ? ret = listen(sock,128); ?

? ? if(ret < 0) ?

? ? { ?

? ? ? ? perror("listen"); ?

? ? ? ? exit(3); ?

? ? } ?

? ? return sock; ?

} ?

??

// ? ? ? poll函數第一個參數類型。 ?

//struct pollfd { ?

// ?int ? fd; ? ? ? ? /* file descriptor */ ?

// ?short events; ? ? /* requested events */ ?

// ?short revents; ? ?/* returned events */ ?

//}; ?

// ?

??

int main(int argc ,char *argv[]) ?

{ ?

? ? if(argc != 3) ?

? ? { ?

? ? ? ? usage(argv[0]); ?

? ? ? ? return 1; ?

? ? } ?

??

? ? int sock = startup(argv[1],atoi(argv[2]) ); ?

? ? struct pollfd peerfd[1024]; //當有就緒事件發生的話會寫到這個數組里面。 ?

??

? ? peerfd[0].fd = sock; ?//首先監聽連接套接字。監聽它的讀事件。 ?

? ? peerfd[0].events = POLLIN; ?

??

? ? int timeout = -1; ?//表示阻塞式等待。 ?

? ? int i = 1; ?

??

? ? for(; i < 1024; ++i) ?

? ? { ?

? ? ? ? peerfd[i].fd = -1; ? ?//表示這個位置么有被占用。 ?

? ? } ?

??

? ? while(1) ?

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

? ? ? ? int ret = 0; ?

? ? ? ? switch(ret = poll(peerfd,1024,timeout)) ?

? ? ? ? { ?

? ? ? ? ? ? case 0: ?

? ? ? ? ? ? ? ? printf("timeout...\n"); ?

? ? ? ? ? ? ? ? break; ?

? ? ? ? ? ? case -1: ?

? ? ? ? ? ? ? ? perror("poll"); ?

? ? ? ? ? ? ? ? break; ?

? ? ? ? ? ? default: ?

? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? int i = 0; ?

? ? ? ? ? ? ? ? ? ? for(i = 0; i < 1024; ++i)//遍歷數組查看有哪些就緒事件發生了。 ?

? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? if(i == 0 && (peerfd[i].revents & POLLIN) ?)//有新的連接請求。 ?

? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? struct sockaddr_in client; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? socklen_t len = sizeof(client); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? int new_sock = accept(sock,(struct sockaddr*)&client,&len); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? if(new_sock < 0) ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? perror("accept"); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? } ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("get a new client\n"); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? int j = 1; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? for(; j < 1024; ++j) ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(peerfd[j].fd < 0) ?//找最小的未被使用的位置。 ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peerfd[j].fd = new_sock; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peerfd[j].events = POLLIN; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? } ?

??

? ? ? ? ? ? ? ? ? ? ? ? ? ? if(j == 1024 ) ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("too many client...\n"); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? close(new_sock); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? } ?

? ? ? ? ? ? ? ? ? ? ? ? } //if ?

? ? ? ? ? ? ? ? ? ? ? ? else if(i != 0) ?

? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? if(peerfd[i].revents & POLLIN) //客戶端有讀事件發生。 ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? char buf[1024]; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ssize_t s = ?read(peerfd[i].fd,buf,sizeof(buf) - 1); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(s > 0) ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? buf[s] = 0; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("clinet say:%s\n",buf); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peerfd[i].events = POLLOUT; //讀完后監聽寫事件。 ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? else if(s <= 0) ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? close(peerfd[i].fd); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peerfd[i].fd = -1; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? } ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? else if(peerfd[i].revents & POLLOUT)//寫事件就緒。 ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? { ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 客戶端寫事件發生 */ ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 使用瀏覽器測試,寫回到客戶端,瀏覽器會解析字符串,顯示 Hellp Epoll! */ ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char* msg = "HTTP/1.1 200 OK\r\n\r\n<html><br/><h1>Hello poll!</h1></html>"; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? write(peerfd[i].fd, msg, strlen(msg)); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //寫完后關閉套接字。 ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? close(peerfd[i].fd); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peerfd[i].fd = -1; ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? } ?

??

? ? ? ? ? ? ? ? ? ? ? ? } //else if ?

??

? ? ? ? ? ? ? ? ? ? } //for ?

??

? ? ? ? ? ? ? ? } //default ?

??

? ? ? ? } //switch() ?

? ? } //while(1) ?

??

? ? return 0; ?

} ?

總結

以上是生活随笔為你收集整理的poll f服务器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。