999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

Linux 下高并發(fā)服務(wù)器的研究與實現(xiàn)

2019-11-03 14:07:16李明陳琳
電腦知識與技術(shù) 2019年23期

李明 陳琳

摘要:Linux作為一個穩(wěn)定、開源、擁有完善的網(wǎng)絡(luò)功能的操作系統(tǒng),在涉及網(wǎng)絡(luò)相關(guān)的軟件開發(fā)時具有得天獨厚的優(yōu)勢。在進(jìn)行網(wǎng)絡(luò)通信程序的開發(fā)時,通常采用 socket 來進(jìn)行網(wǎng)絡(luò)同信。在基于 socket編程的基礎(chǔ)上,對比了 Linux 系統(tǒng)下三種多路復(fù)用 I/O 接口:select、poll、epoll 后。,確定了以 socket、epoll 機制以及線程池為基礎(chǔ)來設(shè)計與實現(xiàn)一個客戶端/服務(wù)器(client/server)模型的高并發(fā)服務(wù)器。基于該模型的基礎(chǔ)上,研究epoll 和事件驅(qū)動模型(Reactor)的實現(xiàn)原理。

關(guān)鍵詞:Linux;epoll;socket;高并發(fā);事件驅(qū)動模型

中圖分類號:TP3? ? ? ?文獻(xiàn)標(biāo)識碼:A

文章編號:1009-3044(2019)23-0259-03

開放科學(xué)(資源服務(wù))標(biāo)識碼(OSID):

1 引言

網(wǎng)絡(luò)上的應(yīng)用程序通常通過“套接字”向網(wǎng)絡(luò)發(fā)出請求或者應(yīng)答請求,建立網(wǎng)絡(luò)通信連接至少需要一對端口號(socket)。Socket 的本質(zhì)是封裝了 TCP/IP 后提供給程序員進(jìn)行網(wǎng)絡(luò)開發(fā)的接口。而要實現(xiàn)高并發(fā)的網(wǎng)絡(luò)通信服務(wù)器,除了掌握 socket 的知識外,還需要了解 I/O 多路復(fù)用機制。作為 Linux 下多路復(fù)用 I/O的機制,select 模型具有最大的并發(fā)數(shù)限制,和效率問題,以及內(nèi)核/用戶控件內(nèi)存拷貝的問題。隨后提出的Poll 模型雖然在 select 機制的基礎(chǔ)上解決了最大并發(fā)數(shù)的限制,但依然存在效率問題和內(nèi)存拷貝的問題。在基于前面二者的基礎(chǔ)上,Linux2.6 版本之后推出了 epoll 模型來解決上述問題。

2 Socket 原理及應(yīng)用

2.1 socket通訊原理

在 Linux 環(huán)境下,Socket 是一種用于表示進(jìn)程間網(wǎng)絡(luò)通信的特殊文件類型。本質(zhì)為內(nèi)核借助緩沖區(qū)形成的偽文件。作為一種全雙工通信的模式,一個文件描述符對應(yīng) socket 的2個緩沖區(qū),一個用于讀,一個用于寫。 在 TCP/IP 協(xié)議中,IP 加端口可以唯一確定一個Socket ,而想要建立連接的額兩個進(jìn)程各自有一個 socket 對應(yīng),這兩個 socket 組成的 socket pair 就可以確定一個唯一的連接。因此可以用 socket 來描述網(wǎng)絡(luò)中的一對一連接關(guān)系。套接字通信原理如圖1所示:

2.2 socket 通信流程

利用 socket 進(jìn)行網(wǎng)絡(luò)通信的 C/S 模型分為客戶端和服務(wù)器端。服務(wù)器端要做的工作主要為創(chuàng)建 socket、綁定 IP 地址和端口、設(shè)置同時最大連接數(shù)、監(jiān)聽并接受客戶端的連接請求、讀取客戶端發(fā)送的數(shù)據(jù)、處理請求、回寫數(shù)據(jù)到客戶端、完成并關(guān)閉這次連接。

客戶端需要進(jìn)行的工作則為創(chuàng)建 socket、建立連接、向服務(wù)器端寫數(shù)據(jù)、讀取服務(wù)器端回寫的數(shù)據(jù)、結(jié)束這次連接。圖二展示了一個完整的網(wǎng)絡(luò)通信的過程。

2.3 TCP 連接的建立與釋放

在實現(xiàn)高并發(fā)的 C/S 模型服務(wù)器是,選擇了TCP作為通信協(xié)議。TCP是一個面向連接的協(xié)議,相對于無連接的 UDP協(xié)議,TCP通過三次握手建立連接的方式在很大程度上保證連接與傳輸?shù)目煽啃浴H挝帐值牧鞒倘缦拢?/p>

l 客戶端向服務(wù)器發(fā)送一個 SYN J

l 服務(wù)器向客戶端發(fā)響應(yīng)一個SYN K, 并對SYN J進(jìn)行確認(rèn) ACK J + 1

l 客戶端再向服務(wù)器端發(fā)送一個確認(rèn) ACK K + 1

而在某個應(yīng)用進(jìn)程完成通信后,就需要釋放連接,而 TCP是通過四次握手來釋放連接。

l 客戶端首先調(diào)用close主動關(guān)閉連接,TCP 發(fā)送一個FIN M

l 服務(wù)端接收 FIN M之后,執(zhí)行被動關(guān)閉,對FIN M進(jìn)行確認(rèn)。

l 一段時間后,接收到文件結(jié)束符的應(yīng)用進(jìn)程調(diào)用 close 關(guān)閉自身的socket,同時發(fā)送一個FIN N

l 接收到 FIN N 的客戶端TCP 對 FIN N進(jìn)行確認(rèn)。

TCP的連接與釋放的示意圖如圖3所示:

3 epoll + 線程池實現(xiàn)高并發(fā)服務(wù)器

3.1 epoll 反應(yīng)堆模型

3.1.1 epoll API詳解

目前。epoll是Linux 大規(guī)模并發(fā)網(wǎng)絡(luò)程序中的熱門首選模型。epoll為開發(fā)者提供了3個系統(tǒng)調(diào)用。它們的定義如下:

#include ;

int epoll_create (int size);

int epoll_ctl (int epfd, int op, int fd, struct epoll_event *event);

int epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout);

通過使用 epoll_create () 函數(shù)來創(chuàng)建一個句柄,并且在系統(tǒng)內(nèi)核維護(hù)了一個紅黑樹和就緒list鏈表。所以在每次調(diào)用epoll_wait時,不需要傳遞整個fd列表給內(nèi)核,epoll_ctl每次只需要進(jìn)行增量式操作即可。在調(diào)用了epoll_create 之后,內(nèi)核已經(jīng)準(zhǔn)備了一個數(shù)據(jù)結(jié)構(gòu)用于存放需要監(jiān)控的 fd,即注冊上來的事件了。

通過 epoll_ctl () 函數(shù)來注冊需要監(jiān)聽的fd以及對應(yīng)的事件類型。在調(diào)用epoll_ctl向句柄上注冊百萬個fd時,epoll_wait依然能夠快速返回并且有效地將觸發(fā)的事件fd返回給用戶,因為在調(diào)用epoll_create時,內(nèi)核除了幫我們在epoll文件系統(tǒng)新建file節(jié)點,同時在內(nèi)核cache創(chuàng)建紅黑樹用于存儲以后由epoll_ctl注冊上來的fd外,另外建立了一個list鏈表用于存儲準(zhǔn)備就緒的事件。當(dāng)epoll_wait被調(diào)用時,只觀察list鏈表有無數(shù)據(jù)即可。如果list鏈表中有數(shù)據(jù)則返回鏈表中數(shù)據(jù),沒有數(shù)據(jù)則等待timeout超時返回。即使在高并發(fā)情況下我們需要監(jiān)控百萬級別的fd時,通常情況下,一次也只返回少量準(zhǔn)備就緒的fd而已。所以每次調(diào)用epoll_wait時只需要從內(nèi)核態(tài)復(fù)制少量就緒的fd到用戶空間即可。

最后通過 epoll_wait () 來將list鏈表上準(zhǔn)備就緒的fd復(fù)制到用戶空間,然后返回給用戶。而該list鏈表是通過給內(nèi)核中斷處理程序注冊一個回調(diào)函數(shù),當(dāng)fd中斷到達(dá)時,就將它放入到list鏈表中。

因此,通過一顆紅黑樹、一張準(zhǔn)備就緒的fd鏈表以及少量的內(nèi)核cache,就解決了高并發(fā)下的fd處理問題。

3.1.2 epoll 反應(yīng)堆模型

epoll除了提供 select/poll 那種I/O事件的水平觸發(fā)外,還提供了邊沿觸發(fā),。通過epoll API 、邊沿觸發(fā)、非阻塞 I/O 的方式加上一個自定義的結(jié)構(gòu)體來實現(xiàn)一個反應(yīng)堆模式進(jìn)一步提高程序的高并發(fā)能力和效率。

Epoll 默認(rèn)方式為水平觸發(fā)即有事件發(fā)生時且緩沖區(qū)中有數(shù)據(jù)可讀或有空間可寫時,則會持續(xù)觸發(fā)直到數(shù)據(jù)處理完畢,而邊沿觸發(fā)則是當(dāng)狀態(tài)發(fā)生改變時則觸發(fā)。通過設(shè)置邊沿觸發(fā)在處理大量數(shù)據(jù)時可以只讀取數(shù)據(jù)頭,在服務(wù)器解析頭部后決定繼續(xù)讀取數(shù)據(jù)還是丟棄處理以此節(jié)省更多服務(wù)器開銷。而為了避免邊沿觸發(fā)導(dǎo)致死鎖的形成,需要配合非阻塞I/O的方式來進(jìn)行處理。

為了實現(xiàn)epoll的反應(yīng)堆模型,需要自定義一個結(jié)構(gòu)體 my_events 來保存相關(guān)的元素。該結(jié)構(gòu)體最少應(yīng)該包含文件描述符、事件類型、一個泛型指針、一個回調(diào)函數(shù)。同時聲明一個該結(jié)構(gòu)體的數(shù)組用于保存連接上來的客戶端。

struct my_events{

int fd;

int events;

void *arg;

void (*call_back)(int fd, int events, void* arg);? ? ? ? ? ? ? ?/

int status;

char buf[BUFLEN];

int len;

long last_active;

};

struct my_events g_events[MAX_EVENTS+1];

通過該結(jié)構(gòu)體中的泛型指針指向這個結(jié)構(gòu)體本身可以使得每個事件擁有自己的回調(diào)函數(shù)。從而使得主程序只負(fù)責(zé)監(jiān)聽就緒的事件,而將數(shù)據(jù)的處理放到回調(diào)函數(shù)中進(jìn)行。epoll Reactor模式的大致流程如下:

l 程序設(shè)置邊沿觸發(fā)和fd的非阻塞I/O

l 利用 epoll_create 來創(chuàng)建一個句柄和內(nèi)部實現(xiàn)的紅黑樹

l 初始化創(chuàng)建并綁定監(jiān)聽 socket,并返回一個文件描述符 listen_fd,并添加到紅黑樹上

l 監(jiān)聽可讀事件(ET) ? 數(shù)據(jù)到來 ? 觸發(fā)事件 ? epoll_wait()返回 ? 讀取完數(shù)據(jù)(可讀事件回調(diào)函數(shù)內(nèi)) ? 將該節(jié)點從紅黑樹上摘下(可讀事件回調(diào)函數(shù)內(nèi)) ? 設(shè)置可寫事件和對應(yīng)可寫回調(diào)函數(shù)(可讀事件回調(diào)函數(shù)內(nèi)) ? 掛上樹(可讀事件回調(diào)函數(shù)內(nèi)) ? 處理數(shù)據(jù)(可讀事件回調(diào)函數(shù)內(nèi))

l 監(jiān)聽可寫事件(ET) ? 對方可讀 ? 觸發(fā)事件 ? epoll_wait()返回 ? 寫完數(shù)據(jù)(可寫事件回調(diào)函數(shù)內(nèi)) ? 將該節(jié)點從紅黑樹上摘下(可寫事件回調(diào)函數(shù)內(nèi)) ? 設(shè)置可讀事件和對應(yīng)可讀回調(diào)函數(shù)(可寫讀事件回調(diào)函數(shù)內(nèi)) ? 掛上樹(可寫事件回調(diào)函數(shù)內(nèi)) ? 處理收尾工作(可寫事件回調(diào)函數(shù)內(nèi))

l 程序循環(huán)執(zhí)行

3.2 線程池

在目前的大多數(shù)網(wǎng)絡(luò)服務(wù)器中,單位時間內(nèi)必須處理數(shù)目巨大的連接請求,但處理時間卻相對較短。傳統(tǒng)的每接收一個請求就創(chuàng)建一個線程的模式在處理大量的短連接,任務(wù)執(zhí)行時間短的連接請求時將會使服務(wù)器長時間處于創(chuàng)建線程和銷毀線程的狀態(tài)中,極大的浪費CPU資源。線程池是一種線程使用模式,線程過多會帶來調(diào)度的開銷進(jìn)而影響緩存局部性和整體性能,而線程池維護(hù)著多個線程,等待著監(jiān)督管理者分配可并發(fā)執(zhí)行的任務(wù)。這避免了在處理短時間任務(wù)時創(chuàng)建與銷毀線程的代價,它保證了內(nèi)核的充分利用,防止了過度調(diào)用。

構(gòu)建一個線程池的框架一般具有如下幾個部分。一個自定義結(jié)構(gòu)體threadpool_t用于描述線程池的相關(guān)信息,包括有用于線程間同步的互斥鎖和信號量、保存工作線程線程號的數(shù)組、一個管理者線程、管理任務(wù)的任務(wù)隊列、以及記錄線程池內(nèi)最小線程數(shù),工作線程數(shù),最大線程數(shù)等的變量。然后定義相關(guān)的函數(shù)API,其中主要的函數(shù)定義如下所示:

1. threadpool_t *threadpool_create(): 用于創(chuàng)建和初始化一個線程池

2. int threadpool_add():用于向線程池的任務(wù)隊列添中加一個任務(wù)

3. void *threadpool_thread():線程池中的各工作線程

4. void *adjust_thread () : 管理者線程,負(fù)責(zé)線程池的維護(hù)

在程序開始時,預(yù)創(chuàng)建一個線程池和最小數(shù)量的線程放入空閑隊列中等待喚醒,在任務(wù)到來之前,線程處于阻塞狀態(tài)不會占用CPU資源,在任務(wù)到達(dá)以后,在線程池中喚醒一個線程來接收此任務(wù)并處理。當(dāng)任務(wù)隊列中任務(wù)較多而當(dāng)前工作線程數(shù)量不夠支撐時,線程池會通過管理者線程向線程池中添加一定數(shù)量的新線程,而當(dāng)空閑線程數(shù)過多而任務(wù)隊里任務(wù)較少時,管理者線程也會從線程中銷毀一部分線程,回收系統(tǒng)資源,動態(tài)的管理線程池。通過這種預(yù)處理技術(shù),線程創(chuàng)建和銷毀帶來的開銷則分?jǐn)偟礁鱾€具體的任務(wù)上,執(zhí)行次數(shù)越多,每個任務(wù)分?jǐn)偟木€程本身開銷越小,達(dá)到了提高系統(tǒng)效率,節(jié)約系統(tǒng)資源的目的。

在實際的應(yīng)用當(dāng)中,線程池并不適用于所有場景。它致力于減少線程本身的開銷對應(yīng)用所產(chǎn)生的影響。但是對于一些任務(wù)執(zhí)行時間較長的服務(wù)例如FTP和TELNET,相較于文件傳輸?shù)臅r間,線程創(chuàng)建和銷毀的開銷可以忽略不計,此時使用線程池并不能帶倆效率上的明顯提高。總結(jié)起來。線程池使用于單位時間內(nèi)處理任務(wù)頻繁且任務(wù)處理事件短、對實時性要求高、以及高突發(fā)性的事件。

4 總結(jié)

通過使用epoll多路I/O復(fù)用,設(shè)置邊沿觸發(fā)和非阻塞的方式,基于事件驅(qū)動模式實現(xiàn)的服務(wù)器已經(jīng)能夠?qū)崿F(xiàn)高并發(fā)的需求,同時將接受到連接請求和具體的任務(wù)通過線程池的方式來處理,進(jìn)一步提高了并發(fā)服務(wù)器的處理效率和并發(fā)能力,同時對與突發(fā)性的訪問量突增的情況也能良好的適應(yīng)與處理。

但是在設(shè)計與實現(xiàn)不同的高并發(fā)服務(wù)器時,epoll和線程池并不適用于所有場景。其他的多路I/O復(fù)用 sleclt/poll加上傳統(tǒng)的“及時創(chuàng)建,及時銷毀“多線程策略也有適合的應(yīng)用場景。因此需要根據(jù)實際情況和不同場景選擇不同的設(shè)計模式,實現(xiàn)最符合需求的并發(fā)服務(wù)器。

參考文獻(xiàn):

[1] Andrew S Tanenbaum, 計算機網(wǎng)絡(luò)[M]. 熊桂喜等譯, 北京:清華大學(xué)出版社,1998.

[2] 陳碩,Linux 多線程服務(wù)端編程[M]. 北京:電子工業(yè)出版社,2013.

[3] 唐富強, 于鴻洋, 張萍.? Linux下通用線程池的改進(jìn)與實現(xiàn)[J].計算機工程與應(yīng)用, 2012, 48(28): 77-78.

[4] 邱杰,朱曉姝,孫小雁. 基于Epoll模型的消息推送研究與實現(xiàn)[J]. 合肥工業(yè)大學(xué)學(xué)報, 2016, 39(4): 476-477.

[5] 余光遠(yuǎn). 基于Epoll的消息推送系統(tǒng)的設(shè)計與實現(xiàn)[D]. 武漢:華中科技大學(xué), 2011.

[6] 張超,潘旭東 Linux下基于EPOLL機制的海量網(wǎng)絡(luò)信息處理模型[J].強激光與粒子束, 2013,25(Z1):46-50.

[7] 楊開杰,劉秋菊,徐汀榮.線程池的多線程并發(fā)控制技術(shù)研究[J].計算機應(yīng)用與軟件,2010,27(1):169-170.

[8] 劉新強,曾兵義.用線程池解決服務(wù)器并發(fā)請求的方案設(shè)計[J].現(xiàn)代電子技術(shù),2011,34(15):142-143.

【通聯(lián)編輯:梁書】

主站蜘蛛池模板: 国产精品密蕾丝视频| 高清亚洲欧美在线看| 亚洲中文无码h在线观看| 蜜芽一区二区国产精品| 免费在线不卡视频| 伊人成色综合网| 亚洲三级影院| 日本欧美成人免费| 高h视频在线| 亚洲无码视频一区二区三区| 亚洲精品少妇熟女| 91偷拍一区| 久久夜夜视频| 亚洲国产中文精品va在线播放| 色网站免费在线观看| 福利在线一区| 波多野结衣无码视频在线观看| 免费一级成人毛片| 黄色在线网| 在线观看视频99| 久久无码高潮喷水| 免费av一区二区三区在线| 亚洲无码精彩视频在线观看| 四虎影视8848永久精品| 五月六月伊人狠狠丁香网| 2020精品极品国产色在线观看 | 国产成人毛片| 久久婷婷国产综合尤物精品| 国产欧美专区在线观看| 久久精品国产一区二区小说| 人妻出轨无码中文一区二区| 亚洲天堂福利视频| 超碰精品无码一区二区| 亚洲人成影院午夜网站| 中国国产高清免费AV片| 欧美成人综合在线| 国内精品伊人久久久久7777人| 国产国模一区二区三区四区| 麻豆精品在线| 四虎精品国产AV二区| 国产二级毛片| 国产一区免费在线观看| 成人伊人色一区二区三区| 国产天天射| 亚洲欧美不卡中文字幕| 四虎影视8848永久精品| 久久国产拍爱| 97在线免费视频| 国内精品久久久久久久久久影视| 亚洲av成人无码网站在线观看| 国产精品露脸视频| 国产极品美女在线| 色妞www精品视频一级下载| 亚洲精品大秀视频| 国产综合日韩另类一区二区| 72种姿势欧美久久久大黄蕉| 欧美日韩在线亚洲国产人| 国产成人精品一区二区三在线观看| 一级爱做片免费观看久久| 日韩麻豆小视频| 在线观看国产精品一区| 亚洲成年人片| 欧美另类视频一区二区三区| 91无码人妻精品一区| 欧美日韩国产成人高清视频| 色网站免费在线观看| 日韩区欧美区| 手机在线看片不卡中文字幕| 色婷婷成人| 国产成人精品优优av| 91区国产福利在线观看午夜| 免费A∨中文乱码专区| 99热这里只有免费国产精品| 97青草最新免费精品视频| 欧美一道本| 91美女视频在线| 亚洲最大综合网| 日本草草视频在线观看| 野花国产精品入口| 精品国产自在在线在线观看| 国产福利一区视频| 免费观看亚洲人成网站|