epoll 原理

https://blog.csdn.net/qwert55kai/article/details/124901367

https://www.zhihu.com/question/486578358/answer/2126762689

https://zhuanlan.zhihu.com/p/366365883 : 這個原理講的最通俗易懂
結(jié)合 https://zhuanlan.zhihu.com/p/533713185?utm_id=0

同步阻塞IO:https://mp.weixin.qq.com/s/cIcw0S-Q8pBl1-WYN0UwnA

一.同步阻塞網(wǎng)絡(luò) IO

  1. 會阻塞的方法

accept() : 接收連接

recv() : 接收數(shù)據(jù)

數(shù)據(jù)包抵達網(wǎng)卡,網(wǎng)卡產(chǎn)生一個硬中斷通知CPU,cpu拿到數(shù)據(jù)處理完(cpu就是簡單處理了一下)會觸發(fā)軟中斷,把數(shù)據(jù)放到對應(yīng)的socket里面 并喚醒該socket對應(yīng)的用戶進程

(每次一個進程專門為了等一個 socket 上的數(shù)據(jù)就得被從 CPU 上拿下來。然后再換上另一個進程。等到數(shù)據(jù) ready 了,睡眠的進程又會被喚醒??偣矁纱芜M程上下文切換開銷,根據(jù)之前的測試來看,每一次切換大約是 3-5 us(微秒)左右。如果是網(wǎng)絡(luò) IO 密集型的應(yīng)用的話,CPU 就不停地做進程切換這種無用功,這種切換很消耗資源。

在服務(wù)端角色上,這種模式完全沒辦法使用。因為這種簡單模型里的 socket 和進程是一對一的。我們現(xiàn)在要在單臺機器上承載成千上萬,甚至十幾、上百萬的用戶連接請求。如果用上面的方式,那就得為每個用戶請求都創(chuàng)建一個進程。相信你在無論多原始的服務(wù)器網(wǎng)絡(luò)編程里,都沒見過有人這么干吧。)

二. 非同步阻塞: IO多路復(fù)用

IO多路復(fù)用:簡單理解就是一個進程監(jiān)聽多個socket

IO多路復(fù)用方案有 select、poll、epoll,性能最好的就是epoll

  1. epoll 對象三個重要字段 : epoll對象 就是 eventpoll內(nèi)核對象

wq(等待隊列鏈表): https://zhuanlan.zhihu.com/p/533713185?utm_id=0

rdllist (就緒鏈表) : http://www.itdecent.cn/p/dd72cceaabc1
接收到某個文件描述符過來數(shù)據(jù)時,那么內(nèi)核將該節(jié)點插入到就緒鏈表里面。
當(dāng) epoll_wait接收到消息,并且將數(shù)據(jù)拷貝到用戶空間,清空就緒鏈表。
如果為LT模式,且必須該節(jié)點確實有事件未處理,那么就會把該節(jié)點重新放入到剛剛刪除掉的且剛準備好的就緒鏈表,epoll_wait馬上返回

rbr(保存了所有socket的紅黑樹):紅黑樹存儲所監(jiān)控的文件描述符的節(jié)點數(shù)據(jù)

2.Socket的等待隊列是干嘛的?

https://www.cnblogs.com/aiwz/p/6333250.html

https://blog.csdn.net/weixin_61631200/article/details/125806161 : 搜索:這個socket對象包含了發(fā)送緩沖區(qū)

Socket的等待隊列主要存放的是等待socket事件的進程。當(dāng)進程執(zhí)行到創(chuàng)建socket的語句時,操作系統(tǒng)會創(chuàng)建一個由文件系統(tǒng)管理的socket對象,這個socket對象包含了發(fā)送緩沖區(qū)、接收緩沖區(qū)、等待隊列等成員。當(dāng)進程需要等待某個socket事件(如數(shù)據(jù)接收、連接等)時,它會被添加到等待隊列中。

等待隊列中的進程會一直處于等待狀態(tài),直到所等待的事件發(fā)生。例如,當(dāng)socket接收到數(shù)據(jù)時,操作系統(tǒng)會將等待隊列上的進程重新放回到工作隊列中,該進程變成運行狀態(tài),繼續(xù)執(zhí)行代碼。

需要注意的是,等待隊列中的進程并不會一直占用CPU資源,而是讓出CPU資源給其他進程或線程運行。這種機制可以避免不必要的CPU資源浪費,并提高系統(tǒng)的效率。

  1. epoll 會把 ep_poll_callback 函數(shù)設(shè)置為 socket 等待隊列里,觸發(fā)事件的回調(diào)函數(shù),這樣就把socket 和 epoll 關(guān)聯(lián)上了: 軟中斷將數(shù)據(jù)收到 socket 的接收隊列后,會通過注冊的這個 ep_poll_callback 函數(shù)來回調(diào),進而通知到 epoll 對象。

系統(tǒng)層面,socket也是交給了epoll管理的

  1. epoll_wait

epoll_wait 做的事情不復(fù)雜,當(dāng)它被調(diào)用時它觀察 eventpoll->rdllist 鏈表里有沒有數(shù)據(jù)即可。有數(shù)據(jù)就返回,沒有數(shù)據(jù)就創(chuàng)建一個等待隊列項,將其添加到 eventpoll 的等待隊列上,然后把自己阻塞掉就完事。

注:這里是添加到eventpoll 的等待l隊列里

在 ep_poll_callback 根據(jù)等待任務(wù)隊列項上的額外的 base 指針可以找到 epitem, 進而也可以找到 eventpoll對象。

首先它做的第一件事就是把自己的 epitem 添加到 epoll 的就緒隊列中。

接著它又會查看 eventpoll 對象上的等待隊列里是否有等待項(epoll_wait 執(zhí)行的時候會設(shè)置)。

如果沒執(zhí)行軟中斷的事情就做完了。如果有等待項,那就查找到等待項里設(shè)置的回調(diào)函數(shù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容