這是學(xué)習(xí)網(wǎng)絡(luò)編程后寫的一個練手的小程序,可以幫助復(fù)習(xí)I/O模型,epoll使用,線程池,HTTP協(xié)議等內(nèi)容。
程序代碼是基于《Linux高性能服務(wù)器編程》一書編寫的。
首先回顧程序中的核心內(nèi)容和主要問題,最后給出相關(guān)代碼。
0. 功能和I/O模型
實現(xiàn)簡易的HTTP服務(wù)端,現(xiàn)僅支持GET方法,通過瀏覽器訪問可以返回相應(yīng)內(nèi)容。
I/O模型采用Reactor(I/O復(fù)用 + 非阻塞I/O) + 線程池。 使用epoll事件循環(huán)用作事件通知,如果listenfd上可讀,則調(diào)用accept,把新建的fd加入epoll中;
是已連接sockfd,將其加入到線程池中由工作線程競爭執(zhí)行任務(wù)。
1. 線程池怎么實現(xiàn)?
程序采用c++編寫,要自己封裝一個簡易的線程池類。大致思路是創(chuàng)建固定數(shù)目的線程(如跟核數(shù)相同),然后類內(nèi)部維護一個生產(chǎn)者—消費者隊列。
提供相應(yīng)的添加任務(wù)(生產(chǎn)者)和執(zhí)行任務(wù)接口(消費者)。按照操作系統(tǒng)書中典型的生產(chǎn)者—消費者模型維護增減隊列任務(wù)(使用mutex和semaphore)。
mutex用于互斥,保證任意時刻只有一個線程讀寫隊列,semaphore用于同步,保證執(zhí)行順序(隊列為空時不要讀,隊列滿了不要寫)。
2. epoll用條件觸發(fā)(LT)還是邊緣觸發(fā)(ET)?
考慮這樣的情況,一個工作線程在讀一個fd,但沒有讀完。如果采用LT,則下一次事件循環(huán)到來的時候,又會觸發(fā)該fd可讀,此時線程池很有可能將該fd分配給其他的線程處理數(shù)據(jù)。
這顯然不是我們想要看到的,而ET則不會在下一次epoll_wait的時候返回,除非讀完以后又有新數(shù)據(jù)才返回。所以這里應(yīng)該使用ET。
當(dāng)然ET用法在《Tinychatserver: 一個簡易的命令行群聊程序》也有總結(jié)過。用法的模式是固定的,把fd設(shè)為nonblocking,如果返回某fd可讀,循環(huán)read直到EAGAIN。
3. 繼續(xù)上面的問題,如果某個線程在處理fd的同時,又有新的一批數(shù)據(jù)發(fā)來(不是老數(shù)據(jù)沒讀完,是來新數(shù)據(jù)了),即使使用了ET模式,因為新數(shù)據(jù)的到來,仍然會觸發(fā)該fd可讀,所以仍然存在將該fd分給其他線程處理的情況。
這里就用到了EPOLLONESHOT事件。對于注冊了EPOLLONESHOT事件的文件描述符,操作系統(tǒng)最大觸發(fā)其上注冊的一個可讀、可寫或者異常事件,且只觸發(fā)一次。
延伸閱讀
- ssh框架 2016-09-30
- 阿里移動安全 [無線安全]玩轉(zhuǎn)無線電——不安全的藍牙鎖 2017-07-26
- 消息隊列NetMQ 原理分析4-Socket、Session、Option和Pipe 2024-03-26
- Selective Search for Object Recognition 論文筆記【圖片目標分割】 2017-07-26
- 詞向量-LRWE模型-更好地識別反義詞同義詞 2017-07-26
- 從棧不平衡問題 理解 calling convention 2017-07-26
- php imagemagick 處理 圖片剪切、壓縮、合并、插入文本、背景色透明 2017-07-26
- Swift實現(xiàn)JSON轉(zhuǎn)Model - HandyJSON使用講解 2017-07-26
- 阿里移動安全 Android端惡意鎖屏勒索應(yīng)用分析 2017-07-26
- 集合結(jié)合數(shù)據(jù)結(jié)構(gòu)來看看(二) 2017-07-26