服務器之poll

poll服務器方法采用將監聽端口用數組存放起來,這樣就不需要輪詢的監聽整個文件描述符了

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);struct pollfd {int fd; /* 文件描述符 */short events; /* 監控的事件 */short revents; /* 監控事件中滿足條件返回的事件 */};POLLIN            普通或帶外優先數據可讀,即POLLRDNORM | POLLRDBANDPOLLRDNORM        數據可讀POLLRDBAND        優先級帶數據可讀POLLPRI         高優先級可讀數據POLLOUT        普通或帶外數據可寫POLLWRNORM        數據可寫POLLWRBAND        優先級帶數據可寫POLLERR         發生錯誤POLLHUP         發生掛起POLLNVAL         描述字不是一個打開的文件nfds             監控數組中有多少文件描述符需要被監控timeout         毫秒級等待-1:阻塞等,#define INFTIM -1                 Linux中沒有定義此宏0:立即返回,不阻塞進程>0:等待指定毫秒數,如當前系統時間精度不夠毫秒,向上取值

如果不再監控某個文件描述符時,可以把pollfd中,fd設置為-1poll不再監控此pollfd,下次返回時,把revents設置為0

?

/* server.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <errno.h>
#include "wrap.h"#define MAXLINE 80
#define SERV_PORT 6666
#define OPEN_MAX 1024int main(int argc, char *argv[])
{int i, j, maxi, listenfd, connfd, sockfd;int nready;ssize_t n;char buf[MAXLINE], str[INET_ADDRSTRLEN];socklen_t clilen;struct pollfd client[OPEN_MAX];struct sockaddr_in cliaddr, servaddr;listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));Listen(listenfd, 20);client[0].fd = listenfd;client[0].events = POLLRDNORM;                     /* listenfd監聽普通讀事件 */for (i = 1; i < OPEN_MAX; i++)client[i].fd = -1;                             /* 用-1初始化client[]里剩下元素 */maxi = 0;                                         /* client[]數組有效元素中最大元素下標 */for ( ; ; ) {nready = poll(client, maxi+1, -1);             /* 阻塞 */if (client[0].revents & POLLRDNORM) {         /* 有客戶端鏈接請求 */clilen = sizeof(cliaddr);connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));for (i = 1; i < OPEN_MAX; i++) {if (client[i].fd < 0) {client[i].fd = connfd;     /* 找到client[]中空閑的位置,存放accept返回的connfd */break;}}if (i == OPEN_MAX)perr_exit("too many clients");client[i].events = POLLRDNORM;         /* 設置剛剛返回的connfd,監控讀事件 */if (i > maxi)maxi = i;                         /* 更新client[]中最大元素下標 */if (--nready <= 0)continue;                         /* 沒有更多就緒事件時,繼續回到poll阻塞 */}for (i = 1; i <= maxi; i++) {             /* 檢測client[] */if ((sockfd = client[i].fd) < 0)continue;if (client[i].revents & (POLLRDNORM | POLLERR)) {if ((n = Read(sockfd, buf, MAXLINE)) < 0) {if (errno == ECONNRESET) { /* 當收到 RST標志時 *//* connection reset by client */printf("client[%d] aborted connection\n", i);Close(sockfd);client[i].fd = -1;} else {perr_exit("read error");}} else if (n == 0) {/* connection closed by client */printf("client[%d] closed connection\n", i);Close(sockfd);client[i].fd = -1;} else {for (j = 0; j < n; j++)buf[j] = toupper(buf[j]);Writen(sockfd, buf, n);}if (--nready <= 0)break;                 /* no more readable descriptors */}}}return 0;
}

client

/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"#define MAXLINE 80
#define SERV_PORT 6666int main(int argc, char *argv[])
{struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd, n;sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);servaddr.sin_port = htons(SERV_PORT);Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));while (fgets(buf, MAXLINE, stdin) != NULL) {Write(sockfd, buf, strlen(buf));n = Read(sockfd, buf, MAXLINE);if (n == 0)printf("the other side has been closed.\n");elseWrite(STDOUT_FILENO, buf, n);}Close(sockfd);return 0;
}

同樣的包含了wrap.c和wrap.h的文件,放在錯誤分析的那個博客中

#include <poll.h>

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

??? struct pollfd {

??????? int fd; /* 文件描述符 */

??????? short events; /* 監控的事件 */

??????? short revents; /* 監控事件中滿足條件返回的事件 */

??? };

??? POLLIN??????? 普通或帶外優先數據可讀,POLLRDNORM | POLLRDBAND

??? POLLRDNORM????? 數據可讀

??? POLLRDBAND????? 優先級帶數據可讀

??? POLLPRI ??????? 高優先級可讀數據

??? POLLOUT?? ??? 普通或帶外數據可寫

??? POLLWRNORM????? 數據可寫

??? POLLWRBAND????? 優先級帶數據可寫

??? POLLERR ????? 發生錯誤

??? POLLHUP ??????? 發生掛起

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

?

??? nfds ?????????? 監控數組中有多少文件描述符需要被監控

?

??? timeout ??????? 毫秒級等待

??????? -1:阻塞等,#define INFTIM -1 ?????????????? Linux中沒有定義此宏

??????? 0:立即返回,不阻塞進程

??????? >0:等待指定毫秒數,如當前系統時間精度不夠毫秒,向上取值

?

轉載于:https://www.cnblogs.com/wanghao-boke/p/11409506.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384848.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384848.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384848.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Mysql數據庫簡單使用(二)

Mysql導入.sql文件 進入數據庫&#xff08;要導入的數據庫&#xff09;數據庫中有要導入.sql文件名的數據庫&#xff0c;沒有則新建。source 路徑文件名souce /home/robot/csql.sql 數據庫文件.sql文件放在/home/robot目錄下 按照時間刪除數據庫數據 DELETE FROM 表名 WHERE 時…

Python3集合

集合&#xff08;set&#xff09;是一個無序的不重復元素序列。 可以使用大括號{ } 或set&#xff08;&#xff09;函數來創建集合&#xff0c;注意&#xff1a;創建一個空集合必須用set(),{ }是用來創建一個空字典的。 創建格式&#xff1a; param {value01,value02,…} set(…

Python3條件判斷

if語句&#xff1a; Python中if語句的一般形式如下&#xff1a; if condition_1:statement_block_1 elif condition_2:statement_block_2 else:statement_block_3 if語句關鍵詞&#xff1a; if – elif – else 注意&#xff1a; 每個條件后面要使用冒號:使用縮進來劃分語句塊&…

Python3循環

Python中while語句的一般形式&#xff1a; while 判斷條件: 語句 同樣需要注意冒號和縮進&#xff0c;另外在Python中沒有do…while循環 下面的實例計算1到100總和 ##calc.py n 100sum 0 counter 1 while counter < n:sum sum countercounter 1print("total from…

Python3迭代器和生成器

迭代器 迭代是Python最強大的功能之一&#xff0c;是訪問元素集合的一種方法。 迭代器是一個可以記住遍歷的位置的對象。 迭代器對象從集合的第一個元素開始訪問&#xff0c;直到所有的元素被訪問完結束&#xff0c;迭代器只能向前不會后退。 迭代器有兩個基本方法&#xff0c;…

Pythton3實例

計算1-100之和 #add.py n 0 sum 0 for n in range(0,101):sum n print(sum) 實現99乘法法則 #mul.py i 1 while i < 9:j 1while j < i:mut j*iprint("%d * %d %d"%(j,i,mut),end" ")j 1print(" ")i 1 運算結果: robotubuntu:~/wa…

Python3函數

函數是組織好的&#xff0c;可重復使用的&#xff0c;用來實現單一&#xff0c;或相關功能的代碼段。 函數能提高應用的模塊性&#xff0c;和代碼的重復使用率。 定義一個函數 可以定義一個由自己想要功能的函數&#xff0c;以下是簡單規則&#xff1a; l 函數代碼塊是以def關…

epoll函數

epoll是Linux下多路復用IO接口select/poll的增強版本&#xff0c;它能顯著提高程序在大量并發連接中只有少量活躍的情況下的系統CPU利用率&#xff0c;因為它會復用文件描述符集合來傳遞結果而不用迫使開發者每次等待事件之前都必須重新準備要被偵聽的文件描述符集合&#xff0…

epoll事件模型

事件模型 EPOLL事件有兩種模型&#xff1a; Edge Triggered (ET) 邊緣觸發只有數據到來才觸發&#xff0c;不管緩存區中是否還有數據。 Level Triggered (LT) 水平觸發只要有數據都會觸發。 思考如下步驟&#xff1a; 假定我們已經把一個用來從管道中讀取數據的文件描述符(RFD)…

epoll反應堆模型代碼

libevent函數庫核心思想 /*** epoll_loop.c ***/ #include<stdio.h> #include<sys/epoll.h> #include<sys/socket.h> #include<arpa/inet.h> #include<fcntl.h> #include<unistd.h> #include<errno.h> #include<string.h> #in…

UDP廣播

廣播是在局域網之間的一對多的通信方式&#xff0c;使用的udp協議 /*** client.c ***/ #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h>#define SERVER_PORT 8000 #define MAXLINE…

UDP組播

多播(組播) 組播組可以是永久的也可以是臨時的。組播組地址中&#xff0c;有一部分由官方分配的&#xff0c;稱為永久組播組。永久組播組保持不變的是它的ip地址&#xff0c;組中的成員構成可以發生變化。永久組播組中成員的數量都可以是任意的&#xff0c;甚至可以為零。那些沒…

Python3數據結構

列表&#xff1a; Python列表是可變的&#xff0c;這是它區別于字符串數組和元組的最重要的特點。列表可以修改&#xff0c;而字符串和元組不能。 以下是Python中列表的描述方法&#xff1a; 方法 描述 list.append(x) 將元素添加到列表結尾 list.extend(L) 通過添加指定列…

sed、awk工具

ed sed意為流編輯器&#xff08;Stream Editor&#xff09;&#xff0c;在Shell腳本和Makefile中作為過濾器使用非常普遍&#xff0c;也就是把前一個程序的輸出引入sed的輸入&#xff0c;經過一系列編輯命令轉換為另一種格式輸出。sed和vi都源于早期UNIX的ed工具&#xff0c;所…

C語言正則表達式

POSIX規定了正則表達式的C語言庫函數&#xff0c;詳見regex(3)。我們已經學習了很多C語言庫函數的用法&#xff0c;讀者應該具備自己看懂man手冊的能力了。本章介紹了正則表達式在grep、sed、awk中的用法&#xff0c;學習要能夠舉一反三&#xff0c;請讀者根據regex(3)自己總結…

makefile通用版本

實際當中程序文件比較大&#xff0c;這時候對文件進行分類&#xff0c;分為頭文件、源文件、目標文件、可執行文件。也就是說通常將文件按照文件類型放在不同的目錄當中&#xff0c;這個時候的Makefile需要統一管理這些文件&#xff0c;將生產的目標文件放在目標目錄下&#xf…

Python3OS文件/方法

Python3OS文件/方法 os模塊提供了非常豐富的方法用來處理文件和目錄。 方法 描述 os.access(path,mode) 檢驗權限模式 os.chdir(path) 改變當前工作目錄 os.chflags(path,flags) 設置路徑的標記為數字標記 os.chmod(path,mode) 更改權限 os.chown(path,uid,gid) 更改…

Python3文件

open()方法 Python open()方法永于打開一個文件&#xff0c;并返回文件對象&#xff0c;并對文件進行處理過程中都需要用到這個方法&#xff0c;如果該文件無法被打開&#xff0c;則拋出OSError 注意&#xff1a;使用open()方法一定要保證關閉文件對象&#xff0c;即調用close(…

Python3輸入輸出

Python兩種輸出值的方式&#xff0c;表達式語句和print()函數。 第三種方式是使用文件對象的write()方法&#xff0c;標準輸出文件可以用sys.stdout的引用。 如果你希望輸出的形式更加多樣&#xff0c;可以使用str.fomat()函數來格式化輸出值。 如果你希望將輸出的值轉化成字符…

動態庫加載順序

1.編譯目標代碼時指定的動態庫搜索路徑&#xff1b; 2.環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑&#xff1b; 3.配置文件/etc/ld.so.conf中指定的動態庫搜索路徑&#xff1b; 4.默認的動態庫搜索路徑/lib&#xff1b; 5.默認的動態庫搜索路徑/usr/lib。 轉載于:https://ww…