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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型

發布時間:2023/11/27 生活经验 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 在《樸素、Select、Poll和Epoll網絡編程模型實現和分析——Select模型》中,我們分析了它只能支持1024個連接同時處理的原因。但是在有些需要同時處理更多連接的情況下,1024個連接往往是不夠的,也就是不能夠高并發。那么這個時候我們就可以采用本文介紹的Poll模型。(轉載請指明出于breaksoftware的csdn博客)

? ? ? ? 在使用Poll模型之前,我們需要定義一個保存連接信息的數組

	struct pollfd fds[FDS_COUNT];

? ? ? ? 之后創建異步監聽socket、綁定端口和監聽端口等行為和《樸素、Select、Poll和Epoll網絡編程模型實現和分析——Select模型》一文中一模一樣,本文就不列出代碼了。我們把創建的socket信息賦值給fds數組的第一個元素,并且設定我們需要關注的事件POLLIN——可讀。

	int timeout;int cur_fds_count;int rc;int index;int expect_events;int error_events;
……// 創建socketmemset(fds, 0, sizeof(fds));error_events = POLLERR | POLLNVAL;expect_events = POLLIN;fds[0].fd = listen_sock;fds[0].events = expect_events;cur_fds_count = 1;

? ? ? ? cur_fds_count用于記錄當前fds數組中有多少個被關心的文件描述符。因為一開始我們只關心監聽socket,所以它的初始值是1。

? ? ? ? 然后我們就要在一個死循環中,不停的調用poll函數,監控我們關心的文件描述符是否發生了狀態改變

	timeout = (500);	while (1) {rc = poll(fds, cur_fds_count, timeout);if (rc < 0) {perror("poll error\n");exit(EXIT_FAILURE);};if (rc == 0) {//perror("poll timeout\n");};

? ? ? ? poll函數的返回值和select函數類似。如果返回小于0,則說明發生了錯誤,我們讓程序退出。如果返回了0,則說明poll函數超時。如果大于0,則說明被關心的文件描述符狀態發生了改變。但是此時,我們仍然不知道是哪個文件描述符發生了改變,所以我們要遍歷fds數組。

		int cur_fds_count_temp = cur_fds_count;for (index = 0; index < cur_fds_count_temp; ++index) {

? ? ? ? 這個時候我們有必要說明下pollfd結構體的定義

struct pollfd {int fd;short events;short revents;
};

? ? ? ? pollfd中的fd是用于記錄我們關心的文件描述符;events表示我們關心的事件,如POLLIN、POLLOUT等。revents是實際發生的事件。于是我們一開始要判斷改pollfd是否發生了事件改變

			if (fds[index].revents == 0) {continue;}

? ? ? ? 接著我們判斷下發生的事件是否是我們定義的出錯事件。

			if (fds[index].revents & error_events) {perror("revents error");

? ? ? ? 如果出錯的是監聽socket,則我們退出程序。

				if (fds[index].fd == listen_sock) {perror("listen sock error");exit(EXIT_FAILURE);}

? ? ? ? 如果出錯的不是監聽socket,則它就是客戶端接入的socket,我們將它關閉,并且將fds數組的最后一個元素覆蓋當前位置,讓數組長度減一。這個過程是最精簡的數組縮小方式,如果使用新數組去記錄,將導致效率降低。

				else {close(fds[index].fd);cur_fds_count--;if (index < cur_fds_count) {memcpy(&fds[index], &fds[cur_fds_count], sizeof(fds[cur_fds_count]));memset(&fds[cur_fds_count], 0, sizeof(fds[cur_fds_count]));index--;}cur_fds_count_temp--;continue;}	}

? ? ? ? 我們再看發生的事件是否是我們關心的事件,如果不是,則continue掉,繼續處理下一個pollfd。

			if (!(fds[index].revents & fds[index].events)) {continue;}

? ? ? ? 經過上述篩選,剩下的就是我們要正常處理的pollfd了。和Select方式一樣,我們先看看其是否是監聽socket。如果是,則獲取客戶端接入的socket值,并記錄到數組中。

			if (fds[index].fd == listen_sock) {int new_sock;new_sock = accept(listen_sock, NULL, NULL);if (new_sock < 0) {//perror("accept error");if (errno != EWOULDBLOCK) {continue;}exit(EXIT_FAILURE);}else {request_add(1);//set_block_filedes_timeout(new_sock);if (cur_fds_count + 1 < sizeof(fds)) {fds[cur_fds_count].fd = new_sock;fds[cur_fds_count].events = expect_events;cur_fds_count++;}}}

? ? ? ? 如果不是監聽socket,則是客戶端接入的socket。我們就讀取這個socket中的內容,并寫入我們的回包。

			else {if (0 == server_read(fds[index].fd)) {server_write(fds[index].fd);}close(fds[index].fd);cur_fds_count--;if (index < cur_fds_count) {memcpy(&fds[index], &fds[cur_fds_count], sizeof(fds[cur_fds_count]));memset(&fds[cur_fds_count], 0, sizeof(fds[cur_fds_count]));index--;}cur_fds_count_temp--;}}}return 0;
}

? ? ? ? 如此,我們便將簡單的poll服務器給寫完了。我們看下poll模型的處理能力。采用和《樸素、Select、Poll和Epoll網絡編程模型實現和分析——樸素模型》一文中相同的環境和壓力,我們看下服務器的數據輸出

? ? ? ? 再看下客戶端的輸出

? ? ? ?可見當前環境下poll模型的處理能力大概是每秒7500次請求。

總結

以上是生活随笔為你收集整理的朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型的全部內容,希望文章能夠幫你解決所遇到的問題。

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