0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

講一下TCP底層的收發(fā)過程

冬至子 ? 來源:周末程序猿 ? 作者:周末程序猿 ? 2023-08-01 17:24 ? 次閱讀

我們繼續(xù)探索高性能網(wǎng)絡(luò)編程,但是我覺得在談系統(tǒng)API之前可以先講一些Linux底層的收發(fā)包過程,如下這是一個(gè)簡(jiǎn)單的socket編程代碼:

int main() {
    ... 

    fd = socket(AF_INET, SOCKET_STREAM, 0);
    bind(fd, ...);
    listen(fd, ...);

    // 如何建立連接
    ...
    afd = accept(fd, ...);

    // 如何接收數(shù)據(jù)
    ...
    read(afd, ...);

    // 如何發(fā)送數(shù)據(jù)
    ...
    send(afd, ...);

    // 如何關(guān)閉連接
    ...
    close(fd);
    ...
}

第一部分:如何建立連接

圖片

從上一篇文章我們介紹了網(wǎng)絡(luò)協(xié)議,我們知道TCP/IP協(xié)議族劃分了應(yīng)用層、TCP傳輸層、IP網(wǎng)絡(luò)層、鏈路層(以太層驅(qū)動(dòng))。

如上圖看應(yīng)用層,通常在網(wǎng)絡(luò)編程中我們需要調(diào)用accept的API建立TCP連接,那TCP如何做的呢?

圖片

從上圖的流程可以看到:
(1)client端發(fā)起TCP握手,發(fā)送syn包;
(2)內(nèi)核收到包以后先將當(dāng)前連接的信息插入到網(wǎng)絡(luò)的SYN隊(duì)列;
(3)插入成功后會(huì)返回握手確認(rèn)(SYN+ACK);
(4)client端如果繼續(xù)完成TCP握手,回復(fù)ACK確認(rèn);
(5)內(nèi)核會(huì)將TCP握手完成的包,先將對(duì)應(yīng)的連接信息從SYN隊(duì)列取出;
(6)將連接信息丟入到ACCEPT隊(duì)列;
(7)應(yīng)用層sever通過系統(tǒng)調(diào)用accept就能拿到這個(gè)連接,整個(gè)網(wǎng)絡(luò)套接字連接完成;

那基于這個(gè)圖,我想問問讀者這里會(huì)有什么問題么?
細(xì)心的讀者應(yīng)該可以看出:
1、這里有兩個(gè)隊(duì)列,必然會(huì)有滿的情況,那如果遇到這種情況內(nèi)核是怎么處理的呢?

(1)如果SYN隊(duì)列滿了,內(nèi)核就會(huì)丟棄連接;
(2)如果ACCEPT隊(duì)列滿了,那內(nèi)核不會(huì)繼續(xù)將SYN隊(duì)列的連接丟到ACCEPT隊(duì)列,如果SYN隊(duì)列足夠大,client端后續(xù)收發(fā)包就會(huì)超時(shí);
(3)如果SYN隊(duì)列滿了,就會(huì)和(1)一樣丟棄連接;

2、如何控制SYN隊(duì)列和ACCEPT隊(duì)列的大???

(1)內(nèi)核2.2版本之前通過listen的backlog可以設(shè)置SYN隊(duì)列(半連接狀態(tài)SYN_REVD)和ACCEPT隊(duì)列(完全連接狀態(tài)ESTABLISHED)的上限;
(2)內(nèi)核2.2版本以后backlog只是表示ACCEPT隊(duì)列上限,SYN隊(duì)列的上限可以通過/proc/sys/net/ipv4/tcp_max_syn_backlog設(shè)置;

3、server端通過accept一直等,豈不是會(huì)卡住收包的線程?

在linux網(wǎng)絡(luò)編程中我們都會(huì)追求高性能,accept如果卡住接收線程,性能會(huì)上不去,所以socket編程中就會(huì)有阻塞和非阻塞模式。
(1)阻塞模式下的accept就會(huì)卡住,當(dāng)前線程什么事情都干不了;
(2)非阻塞模式下,可以通過輪詢accept去處理其他的事情,如果返回EAGAIN,就是ACCEPT隊(duì)列為空,如果返回連接信息,就是可以處理當(dāng)前連接;

第二部分:接收數(shù)據(jù)

圖片

(1)當(dāng)網(wǎng)卡接收到報(bào)文并判斷為TCP協(xié)議后,將會(huì)調(diào)用到內(nèi)核的tcp_v4_rcv方法,如果數(shù)據(jù)按順序收到S1數(shù)據(jù)包,則直接插入receive隊(duì)列中;
(2)當(dāng)收到了S3數(shù)據(jù)包,在第1步結(jié)束后,應(yīng)該收到S2序號(hào),但是報(bào)文是亂序進(jìn)來的,則將S3插入out_of_order隊(duì)列(這個(gè)隊(duì)列存儲(chǔ)亂序報(bào)文);
(3)接下來收到S2數(shù)據(jù)包,如第1步直接進(jìn)入receive隊(duì)列,由于此時(shí)out_of_order隊(duì)列不像第1步是空的,所以引發(fā)了接來的第4步;
(4)每次向receive隊(duì)列插入報(bào)文時(shí)都會(huì)檢查out_of_order隊(duì)列,如果遇到期待的序號(hào)S3,則從out_of_order隊(duì)列摘除,寫入到receive隊(duì)列;
(5)現(xiàn)在應(yīng)用程序開始調(diào)用recv方法;
(6)經(jīng)過層層封裝調(diào)用,接收TCP消息最終會(huì)走到tcp_recvmsg方法;
(7)現(xiàn)在需要拷貝數(shù)據(jù)從內(nèi)核態(tài)到用戶態(tài),如果receive隊(duì)列為空,會(huì)先檢查SO_RCVLOWAT這個(gè)閥值(0表示收到指定的數(shù)據(jù)返回,1表示只要讀取到數(shù)據(jù)就返回,系統(tǒng)默認(rèn)是1),如果已經(jīng)拷貝的字節(jié)數(shù)到現(xiàn)在還小于它,那么可能導(dǎo)致進(jìn)程會(huì)休眠,等待拷貝更多的數(shù)據(jù);
(8)將數(shù)據(jù)從內(nèi)核態(tài)拷貝到用戶態(tài),recv返回拷貝數(shù)據(jù)的大?。?br /> (9)為了選擇降低網(wǎng)絡(luò)包延時(shí)或者提升吞吐量,系統(tǒng)提供了tcp_low_latency參數(shù),如果為0值,用戶暫時(shí)沒有讀數(shù)據(jù)則數(shù)據(jù)包進(jìn)入prequeue隊(duì)列,提升吞吐量,否則不使用prequeue隊(duì)列,進(jìn)入tcp_v4_do_rcv,降低延時(shí);

第三部分:發(fā)送數(shù)據(jù)

圖片

(1)假設(shè)調(diào)用send方法來發(fā)送大于一個(gè)MSS(比如2K)的數(shù)據(jù);
(2)內(nèi)核調(diào)用tcp_sendmsg,實(shí)現(xiàn)復(fù)制數(shù)據(jù),寫入隊(duì)列和組裝tcp協(xié)議頭;
(3)在調(diào)用tcp_sendmsg先需要在內(nèi)核獲取skb,將用戶態(tài)數(shù)據(jù)拷貝到內(nèi)核態(tài),內(nèi)核真正執(zhí)行報(bào)文的發(fā)送,與send方法的調(diào)用并不是同步的,即send方法返回成功,也不一定把IP報(bào)文都發(fā)送到網(wǎng)絡(luò)中了。因此,需要把用戶需要發(fā)送的用戶態(tài)內(nèi)存中的數(shù)據(jù),拷貝到內(nèi)核態(tài)內(nèi)存中,不依賴于用戶態(tài)內(nèi)存,也使得進(jìn)程可以快速釋放發(fā)送數(shù)據(jù)占用的用戶態(tài)內(nèi)存。但這個(gè)拷貝操作并不是簡(jiǎn)單的復(fù)制,而是把待發(fā)送數(shù)據(jù),按照MSS來劃分成多個(gè)盡量達(dá)到MSS大小的分片報(bào)文段,復(fù)制到內(nèi)核中的sk_buff結(jié)構(gòu)來存放;
(4)將數(shù)據(jù)拷貝到發(fā)送隊(duì)列中tcp_write_queue;
(5)調(diào)用tcp_push發(fā)送數(shù)據(jù)到IP層,這里主要滑動(dòng)窗口,慢啟動(dòng),擁塞窗口的控制和判斷是否使用Nagle算法合并小報(bào)文(上一篇已經(jīng)有介紹);
(6)組裝IP報(bào)文頭,通過經(jīng)過iptables或者tcpdump等netfilter模塊過濾,將數(shù)據(jù)交給鄰居子系統(tǒng)(主要功能是查找需要發(fā)送的MAC地址,發(fā)送arp請(qǐng)求,封裝MAC頭等);
(7)調(diào)用網(wǎng)卡驅(qū)動(dòng)程序?qū)?shù)據(jù)發(fā)送出去;

第四部分:關(guān)閉連接

關(guān)閉連接就是TCP揮手過程,我們都知道TCP連接是一種可靠的連接,那如何才能完整可靠的完成關(guān)閉連接呢?linux系統(tǒng)提供了兩個(gè)函數(shù):

  • close對(duì)應(yīng)tcp_close方法,通過減少socket的引用次數(shù)實(shí)現(xiàn)關(guān)閉,僅當(dāng)引用計(jì)數(shù)為0時(shí)才會(huì)觸發(fā)tcp_close;
    圖片
  • shutdown對(duì)應(yīng)tcp_shutdown方法,不關(guān)心socket被引用次數(shù),直接關(guān)閉對(duì)應(yīng)的連接;
    圖片

(1)shutdown可攜帶一個(gè)參數(shù),取值有3個(gè),分別意味著:只關(guān)閉讀、只關(guān)閉寫、同時(shí)關(guān)閉讀寫;

(2)若shutdown的是半打開的連接,則發(fā)出RST來關(guān)閉連接;
(3)若shutdown的是正常連接,那么關(guān)閉讀其實(shí)與對(duì)端是沒有關(guān)系的;
(4)若參數(shù)中有標(biāo)志位為關(guān)閉寫,那么下面做的事與close是一致的,發(fā)出FIN包,告訴對(duì)方本機(jī)不會(huì)再發(fā)消息了;

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 驅(qū)動(dòng)器
    +關(guān)注

    關(guān)注

    51

    文章

    7998

    瀏覽量

    145017
  • 連接器
    +關(guān)注

    關(guān)注

    98

    文章

    13845

    瀏覽量

    135086
  • Linux系統(tǒng)
    +關(guān)注

    關(guān)注

    4

    文章

    587

    瀏覽量

    27181
  • RST
    RST
    +關(guān)注

    關(guān)注

    0

    文章

    31

    瀏覽量

    7359
  • TCP通信
    +關(guān)注

    關(guān)注

    0

    文章

    146

    瀏覽量

    4184
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    一講TCP三次握手和四次揮手

    如果你學(xué)過網(wǎng)絡(luò)基礎(chǔ)知識(shí),那么你定對(duì)TCP三次握手不陌生。今天我想用通俗的話來給大家一講TCP三次握手和四次揮手。畢竟,這個(gè)知識(shí)點(diǎn)在面試時(shí)
    的頭像 發(fā)表于 02-03 10:43 ?2583次閱讀
    <b class='flag-5'>講</b><b class='flag-5'>一講</b>的<b class='flag-5'>TCP</b>三次握手和四次揮手

    哪位高手能給一下預(yù)分頻的作用 或者有資料的分享一下

    哪位高手能給一下預(yù)分頻的作用或者有資料的分享一下先行謝過
    發(fā)表于 02-10 22:42

    網(wǎng)絡(luò)子系統(tǒng)在鏈路層的收發(fā)過程剖析

    網(wǎng)絡(luò)子系統(tǒng)在鏈路層的收發(fā)過程剖析
    發(fā)表于 08-15 17:58

    求大神給一下電機(jī)驅(qū)動(dòng)原理

    求大神給一下電機(jī)驅(qū)動(dòng)原理越詳細(xì)越好,感謝
    發(fā)表于 02-01 21:02

    MCBSP的收發(fā)過程是如何運(yùn)行的

    MCBSP_rrdy(hMcbsp)為0時(shí),表明DRR中的數(shù)據(jù)已經(jīng)被讀取,x = MCBSP_read(hMcbsp)語句如何理解?整個(gè)MCBSP的收發(fā)過程是如何運(yùn)行的,我理解反了?謝謝,請(qǐng)高手指導(dǎo)指導(dǎo)。
    發(fā)表于 05-25 08:44

    個(gè)嵌入式系統(tǒng)的開發(fā)過程有哪些步驟?

    以MVB為例,解答一下嵌入式系統(tǒng)的開發(fā)過程有哪些步驟?
    發(fā)表于 04-27 06:36

    求大神詳細(xì)介紹一下FPGA嵌入式系統(tǒng)開發(fā)過程中的XBD文件設(shè)計(jì)

    求大神詳細(xì)介紹一下FPGA嵌入式系統(tǒng)開發(fā)過程中的XBD文件設(shè)計(jì)
    發(fā)表于 05-06 08:19

    一下在單片機(jī)開發(fā)過程中使用過的幾種調(diào)試方案

    邊運(yùn)行邊修改參數(shù)呢?調(diào)試的方法有多種,在這就來分別談一下我在開發(fā)過程中使用過的幾種調(diào)試方案。這里的調(diào)試方案也是種交互方案,但此方案不是為了交互而設(shè)計(jì),重在快速地搭建、方便地使用、高
    發(fā)表于 01-14 08:25

    nodemcu的開發(fā)過程是怎樣的

    關(guān)于nodemcu的點(diǎn)點(diǎn)滴滴##### 網(wǎng)絡(luò)協(xié)議之前,我覺得應(yīng)該把nodemcu的開發(fā)過程梳理遍,再說下自己調(diào)試遇到的問題。- 因?yàn)樽约阂彩莿偨佑|lua和esp12,理解上可能會(huì)有很多錯(cuò)誤,希望
    發(fā)表于 02-16 06:25

    簡(jiǎn)單敘述一下STM32CubeIDE的開發(fā)過程

    STM32的資源是怎樣進(jìn)行配置的?STM32CubeIDE的開發(fā)過程是怎樣的?
    發(fā)表于 02-24 06:28

    資源約束產(chǎn)品開發(fā)過程仿真模型

    提出考慮資源約束的產(chǎn)品開發(fā)過程仿真模型。該模型考慮產(chǎn)品開發(fā)過程中的返工迭代以及資源約束,根據(jù)任務(wù)信息控制能力確定任務(wù)資源分配的優(yōu)先級(jí),相對(duì)于Cooper 提出的資源分
    發(fā)表于 04-16 11:36 ?16次下載

    掌握串口通信協(xié)議的收發(fā)過程

    現(xiàn)在我們要做個(gè)實(shí)驗(yàn),將個(gè)字節(jié)從51單片機(jī)發(fā)送到電腦串口調(diào)試助手上。這個(gè)實(shí)驗(yàn)的目的是為了掌握串口通信協(xié)議的收發(fā)過程。
    的頭像 發(fā)表于 12-22 10:02 ?7.9w次閱讀
    掌握串口通信協(xié)議的<b class='flag-5'>收發(fā)過程</b>

    錫膏廠家一下助焊劑的危害有哪些?

    會(huì)成本比較高,這是相對(duì)應(yīng)的,所以大家焊接過程種還是要注意,下面佳金源錫膏廠家一下有哪些危害:助焊劑的危害有:般情況,如果技術(shù)工人接觸到
    的頭像 發(fā)表于 01-10 09:30 ?1537次閱讀
    錫膏廠家<b class='flag-5'>講</b><b class='flag-5'>一下</b>助焊劑的危害有哪些?

    Linux TCP底層收發(fā)過程講解

    我們繼續(xù)探索高性能網(wǎng)絡(luò)編程,但是我覺得在談系統(tǒng)API之前可以先講些Linux底層收發(fā)過程
    發(fā)表于 08-08 15:42 ?330次閱讀
    Linux <b class='flag-5'>TCP</b><b class='flag-5'>底層</b>的<b class='flag-5'>收發(fā)過程</b>講解

    ASIC芯片開發(fā)過程

    電子發(fā)燒友網(wǎng)站提供《ASIC芯片開發(fā)過程.ppt》資料免費(fèi)下載
    發(fā)表于 12-25 10:04 ?1次下載