25张图,一万字,拆解Linux网络包发送过程(超级详细~)
25張圖,一萬字,拆解Linux網絡包發(fā)送過程(超級詳細~)
半年前我以源碼的方式描述了網絡包的接收過程。之后不斷有粉絲提醒我還沒聊發(fā)送過程呢 。好,安排!
在開始今天的文章之前,我先來請大家思考幾個小問題。
- 問1:我們在查看內核發(fā)送數(shù)據(jù)消耗的 CPU 時,是應該看 sy 還是 si ?
- 問2:為什么你服務器上的 /proc/softirqs 里 NET_RX 要比 NET_TX 大的多的多?
- 問3 :發(fā)送網絡數(shù)據(jù)的時候都涉及到哪些內存拷貝操作 ?
這些問題雖然在線上經??吹? ,但我們似乎很少去深究。如果真的能透徹地把這些問題理解到位 ,我們對性能的掌控能力將會變得更強。
帶著這三個問題,我們開始今天對 Linux 內核網絡發(fā)送過程的深度剖析 。還是按照我們之前的傳統(tǒng),先從一段簡單的代碼作為切入。如下代碼是一個典型服務器程序的典型的縮微代碼:
int main(){ fd = socket(AF_INET, SOCK_STREAM, 0); bind(fd, ...); listen(fd, ...); cfd = accept(fd, ...); // 接收用戶請求 read(cfd, ...); // 用戶請求處理 dosometing(); // 給用戶返回結果 send(cfd, buf, sizeof(buf), 0);}今天我們來討論上述代碼中,調用 send 之后內核是怎么樣把數(shù)據(jù)包發(fā)送出去的。本文基于Linux 3.10 ,網卡驅動采用Intel的igb網卡舉例 。
一、Linux 網絡發(fā)送過程總覽
我覺得看 Linux 源碼最重要的是得有整體上的把握,而不是一開始就陷入各種細節(jié) 。
我這里先給大家準備了一個總的流程圖,簡單闡述下 send 發(fā)送了的數(shù)據(jù)是如何一步一步被發(fā)送到網卡的