乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      TCP 系統(tǒng)調(diào)用序列

       jijo 2009-03-24
      TCP/IP 編程接口提供各種系統(tǒng)調(diào)用,以幫助您有效地使用該協(xié)議。TCP 堆棧代碼數(shù)量繁多,深入到內(nèi)核級別的完整調(diào)用序列可以幫助您了解 TCP 堆棧。在本文中,將回顧和學(xué)習(xí)關(guān)于 TCP 調(diào)用序列的詳細(xì)信息,其中包括對 FreeBSD 的引用,以及在用戶級進(jìn)行系統(tǒng)調(diào)用后在 TCP 堆棧中發(fā)生的重要函數(shù)調(diào)用。

      引言

      典型的 TCP 客戶機(jī)和服務(wù)器應(yīng)用程序通過發(fā)布 TCP 系統(tǒng)調(diào)用序列來獲取某些函數(shù)。這些系統(tǒng)調(diào)用包括 socket ()、bind ()listen ()、accept ()、send () 和 receive()。本文介紹在應(yīng)用程序發(fā)布 TCP 系統(tǒng)調(diào)用時在較低級別中發(fā)生的情況,如圖 1 所示。


      圖 1. TCP 應(yīng)用程序進(jìn)行的普通調(diào)用序列
       

      圖 2 顯示了 TCP 系統(tǒng)調(diào)用在物理鏈路上發(fā)出之前進(jìn)行傳播的各個層。


      圖 2. TCP 系統(tǒng)調(diào)用的各個層 
       

      套接字層接收進(jìn)行的任何 TCP 系統(tǒng)調(diào)用。套接字層驗(yàn)證 TCP 應(yīng)用程序傳遞的參數(shù)的正確性。這是一個獨(dú)立于協(xié)議 的層,因?yàn)樯形磳f(xié)議連接到調(diào)用中。

      套接字層下面是協(xié)議層,該層包含協(xié)議的實(shí)際實(shí)現(xiàn)(本例中為 TCP)。當(dāng)套接字層對協(xié)議層進(jìn)行調(diào)用時,將確保對兩個層之間共享的數(shù)據(jù)結(jié)構(gòu)具有獨(dú)占訪問權(quán)限。這樣做是為了避免任何數(shù)據(jù)結(jié)構(gòu)損壞。

      各種網(wǎng)絡(luò)設(shè)備驅(qū)動程序在接口層運(yùn)行,該層從物理鏈路接收數(shù)據(jù),并向物理鏈路傳輸數(shù)據(jù)。

      每個套接字具有一個套接字隊列,并且每個接口具有一個用于數(shù)據(jù)通信的接口隊列。不過,對于整個協(xié)議層,只有一個稱為 IP 輸入隊列的協(xié)議隊列。接口層通過此 IP 輸入隊列將數(shù)據(jù)輸入到協(xié)議層。協(xié)議層使用相應(yīng)的接口隊列將數(shù)據(jù)輸出到接口。

      在本文中,將學(xué)習(xí)以下系統(tǒng)調(diào)用:

      Socket

      socket (struct proc *p, struct socket_args *uap, int retval)
                      struct sock_args
                      {
                      int domain,
                      int type,
                      int protocol;
                      };
                      

      在 socket 系統(tǒng)調(diào)用中:

      • p 是一個指針,指向進(jìn)行 socket 調(diào)用的進(jìn)程的 proc 結(jié)構(gòu)。
      • uap 是一個指向 socket_args 結(jié)構(gòu)的指針,該結(jié)構(gòu)包含傳遞到 socket 系統(tǒng)調(diào)用中的進(jìn)程的參數(shù)。
      • retval 是系統(tǒng)調(diào)用的返回值。

       

      socket 系統(tǒng)調(diào)用通過分配新的描述符創(chuàng)建新的套接字。將新的描述符返回到調(diào)用進(jìn)程。任何后續(xù)的系統(tǒng)調(diào)用都使用創(chuàng)建的套接字標(biāo)識。socket 系統(tǒng)調(diào)用還向創(chuàng)建的套接字描述符分配協(xié)議。

      domaintype 和 protocol 參數(shù)值指定系列、類型和協(xié)議,以分配給創(chuàng)建的套接字。圖 3 顯示了調(diào)用序列。


      圖 3. 用于 socket 系統(tǒng)調(diào)用的調(diào)用序列
       

      從進(jìn)程檢索參數(shù)后,socket 函數(shù)調(diào)用 socreate 函數(shù)。socreate 函數(shù)根據(jù)進(jìn)程指定的參數(shù)發(fā)現(xiàn)指向協(xié)議切換 protsw 結(jié)構(gòu)的指針。socreate 函數(shù)然后分配新的套接字結(jié)構(gòu)。然后進(jìn)行協(xié)議特定的調(diào)用 pr_usrreq,進(jìn)而切換到與套接字描述符關(guān)聯(lián)的相應(yīng)協(xié)議特定的請求。pr_usrreq 函數(shù)的原型為:

      int  pr_usrreq(struct socket *so , int req, struct mbuf  *m0 , *m1 , *m2);
                      

      在 pr_usrreq 函數(shù)中:
      • so 是指向套接字結(jié)構(gòu)的指針。
      • req 的功能是標(biāo)識請求。本例中為 PRU_ATTACH。
      • m0m1 和 m2 是指向 mbuf 結(jié)構(gòu)的指針。值因請求而異。

      pr_usrreq 函數(shù)為大約 16 個請求提供服務(wù)。

      tcp_usrreq() 函數(shù)調(diào)用 tcp_attach( ),以處理 PRU_ATTACH 請求。要分配 Internet 協(xié)議控制塊,可調(diào)用in_pcballoc()。在 in_pcballoc 中,調(diào)用了內(nèi)核的內(nèi)存分配器函數(shù),該函數(shù)將內(nèi)存分配給 Internet 控制塊。完成所有必要的 Internet 控制塊結(jié)構(gòu)指針初始化之后,該控制返回到 tcp_attach()。

      分配新的 TCP 控制塊,并在 tcp_newtcpcb() 中初始化。它還初始化所有的 TCP 定時器變量,并且控制返回到 tcp_attach()?,F(xiàn)在套接字狀態(tài)初始化為 CLOSED。在返回到 tcp_usrreq 函數(shù)時,創(chuàng)建套接字描述符,以指向套接字的 TCP 控制塊。

      Internet 控制塊是雙向鏈接的循環(huán)鏈表,其指針指向套接字結(jié)構(gòu),同時套接字結(jié)構(gòu)的 so_pcb 部分指向 Internet 控制塊結(jié)構(gòu)。Internet 控制塊還具有指向 TCP 控制塊的指針。有關(guān) Internet 控制塊和 TCP 控制塊結(jié)構(gòu)的更詳細(xì)信息,請參見參考資料部分。

      Bind

      bind (struct proc *p, struct bind_args *uap, int *retval)
                      struct bind_args
                      {   int s;
                      caddr_t name;
                      int namelen;
                      };
                      

      在 bind 系統(tǒng)調(diào)用函數(shù)中:

      • s 是套接字描述符。
      • name 是指向包含網(wǎng)絡(luò)傳輸?shù)刂返木彌_區(qū)的指針。
      • namelen 是緩沖區(qū)的大小。

      bind 系統(tǒng)調(diào)用將本地網(wǎng)絡(luò)傳輸?shù)刂放c套接字關(guān)聯(lián)。對于客戶端進(jìn)程,發(fā)布 bind 調(diào)用不是強(qiáng)制的。當(dāng)客戶端進(jìn)程發(fā)布 connect 系統(tǒng)調(diào)用時,內(nèi)核負(fù)責(zé)執(zhí)行隱式綁定。服務(wù)器進(jìn)程接受連接或啟動與客戶端的通信之前,發(fā)布顯式綁定請求通常是必需的。

      bind 調(diào)用將進(jìn)程指定的本地地址復(fù)制到 mbuf,并調(diào)用 sobind,后者則根據(jù)請求使用 PRU_BIND 調(diào)用tcp_usrreq()。tcp_usrreq() 中的切換實(shí)例調(diào)用 in_pcbbind(),后者將本地地址和端口號綁定到套接字。in_pcbbind 函數(shù)首先執(zhí)行一些完整性檢查,以確保不綁定套接字兩次,并且至少一個接口分配了 IP 地址。in_pcbbind 負(fù)責(zé)隱式和顯式綁定。

      如果對 in_pcbbind()(指向 sockaddr_in 結(jié)構(gòu)的指針)的調(diào)用中的第二個參數(shù)為非空,則發(fā)生顯式綁定。其他情況下,則發(fā)生隱式綁定。對于顯式綁定,在綁定的 IP 地址上執(zhí)行檢查,并相應(yīng)設(shè)置套接字選項。


      圖 4. 用于 bind 系統(tǒng)調(diào)用的調(diào)用序列
      點(diǎn)擊查看原始尺寸 

      如果指定的本地端口是一個非零值,則對超級用戶特權(quán)進(jìn)行檢查,以確定綁定是否位于保留的端口(例如,根據(jù) Berkley 約定,端口號 < 1024)。然后調(diào)用 in_pcblookup(),以便查找具有提到的本地 IP 地址和本地端口號的控制塊。in_pcblookup() 驗(yàn)證本地地址和端口對是否仍未使用。如果 in_pcbbind() 中的第二個參數(shù)是 NULL,或本地端口是零,則控制失敗,并檢查臨時端口(例如,根據(jù) Berkley 約定,1024 < 端口號 < 5000)。然后調(diào)用 in_pcblookup(),以驗(yàn)證發(fā)現(xiàn)的端口是否未使用。

      Listen

      listen (struct proc *p, struct listen_args *uap, int *retval)
                      struct listen_args
                      { int s;
                      int backlog;
                      };
                      

      在 listen 系統(tǒng)調(diào)用中:

      • s 是套接字描述符。
      • backlog 是套接字上的連接數(shù)的隊列限制。

      listen 調(diào)用指示協(xié)議,服務(wù)器進(jìn)程準(zhǔn)備接受套接字上任何新傳入的連接。存在一個可以排列的連接數(shù)限制,在該連接數(shù)之后,忽略任何進(jìn)一步的連接請求。

      listen 系統(tǒng)調(diào)用使用套接字描述符和 listen 調(diào)用中指定的backlog 值調(diào)用 solisten。solisten 僅使用 PRU_LISTEN 作為請求調(diào)用 tcp_usrreq 函數(shù)。在 tcp_usrreq() 函數(shù)的切換語句中,PRU_LISTEN 的實(shí)例檢查套接字是否綁定到端口。如果端口為零,則調(diào)用 in_pcbbind(),將套接字綁定到一個端口(按照 Bind 部分中的描述)。

      如果端口上已存在偵聽的套接字,則將套接字的狀態(tài)更改為 LISTEN。通常,所有的服務(wù)器進(jìn)程都偵聽眾所周知的端口號。很少調(diào)用in_pcbbind 來執(zhí)行服務(wù)器進(jìn)程的隱式綁定。圖 5 顯示了偵聽的調(diào)用序列。


      圖 5. 用于 listen 系統(tǒng)調(diào)用的調(diào)用序列
       

      Accept

      accept(struct proc *p, struct accept_args *uap, int *retval);
                      struct  accept_args
                      {
                      int s;
                      caddr_t name;
                      int *anamelen;
                      };
                      

      在 accept 系統(tǒng)調(diào)用中:

      • s 是套接字描述符。
      • name 是緩沖區(qū)(OUT 參數(shù)),它包含外來主機(jī)的網(wǎng)絡(luò)傳輸?shù)刂贰?/li>
      • anamelen 是 name 緩沖區(qū)的大小。

      accept 系統(tǒng)調(diào)用是等待傳入連接的阻塞調(diào)用。處理連接請求后,accept 將返回新的套接字描述符。將此新的套接字連接到客戶端,使另外一個套接字 s 保持 LISTEN 狀態(tài),以接受進(jìn)一步連接。


      圖 6. 用于 accept 系統(tǒng)調(diào)用的調(diào)用序列
      點(diǎn)擊查看原始尺寸 

      accept 調(diào)用首先驗(yàn)證參數(shù),并等待要到達(dá)的連接請求。在此之前,函數(shù)在 while 循環(huán)中阻塞。新的連接到達(dá)后,協(xié)議層喚醒服務(wù)器進(jìn)程。Accept 然后檢查函數(shù)阻塞時發(fā)生的任何套接字錯誤。如果存在任何套接字錯誤,則函數(shù)返回,并繼續(xù)從隊列拾取新的連接并調(diào)用soaccept。在 soaccept() 中調(diào)用 tcp_usrreq () 函數(shù),并將請求作為 PRU_ACCEPT。tcp_usrreq 函數(shù)中的切換調(diào)用in_setpeeraddr(),后者從協(xié)議控制塊復(fù)制外來 IP 地址和外來端口號,并將其返回到服務(wù)器進(jìn)程。

      Connect

      connect (struct proc *p, struct connect_args *uap, int *retval);
                      struct connect_args
                      {
                      int s;
                      caddr_t name;
                      int namelen;
                      };
                      

      在 connect 系統(tǒng)調(diào)用中:

      • s 是套接字描述符。
      • name 是指向具有外來 IP/端口地址對的緩沖區(qū)的指針。
      • namelen 是緩沖區(qū)的長度。

      客戶端進(jìn)程通常調(diào)用 connect 系統(tǒng)調(diào)用,以連接到服務(wù)器進(jìn)程。如果在初始化連接之前,客戶端進(jìn)程沒有顯式發(fā)布 bind 系統(tǒng)調(diào)用,則堆棧負(fù)責(zé)本地套接字上的隱式綁定。

      connect 系統(tǒng)調(diào)用將外來地址(需要將連接請求發(fā)送到地址)從進(jìn)程復(fù)制到內(nèi)核,并調(diào)用 soconnect()。從 soconnect() 返回時,connect() 函數(shù)進(jìn)入睡眠狀體,直到協(xié)議層將其喚醒,并指示連接是 ESTABLISHED 或套接字上存在錯誤。soconnect() 函數(shù)檢查套接字的有效狀態(tài),并使用 PRU_CONNECT 作為請求調(diào)用 pr_usrreq()

      tcp_usrreq() 函數(shù)中的切換實(shí)例檢查套接字與本地端口的綁定。如果未綁定套接字,則調(diào)用執(zhí)行隱式綁定的 in_pcbbind()。然后調(diào)用 in_pcbconnect(),以獲取到達(dá)目的地的路線,發(fā)現(xiàn)必須輸出套接字的接口,并驗(yàn)證 connect() 指定的外來套接字對(IP 地址和端口號)是否唯一。然后使用外來 IP 地址和端口號更新其 Internet 控制塊,并返回到 PRU_CONNECT 示例語句。

      tcp_usrreq () 現(xiàn)在調(diào)用 soisconnecting (),它可以將客戶端主機(jī)上的套接字的狀態(tài)設(shè)置為 SYN_SENT。調(diào)用函數(shù)tcp_output,將 SYN 包輸出到網(wǎng)絡(luò)??刂片F(xiàn)在返回到 connect() 函數(shù),該函數(shù)處于睡眠狀態(tài),直到協(xié)議層喚醒 — 指示連接現(xiàn)在是 ESTABLISHED,或套接字上存在錯誤。


      圖 7. 用于 connect 系統(tǒng)調(diào)用的調(diào)用序列
      點(diǎn)擊查看原始尺寸 

      3 向 TCP 握手

      圖 8、圖 9 和圖 10 顯示了客戶端發(fā)布 connect 和服務(wù)器發(fā)布 accept 以指示和建立 TCP 連接時的調(diào)用序列。


      圖 8. 用于 SYN 包的流序列
      點(diǎn)擊查看原始尺寸 

      當(dāng)客戶端發(fā)布 connect 時,在協(xié)議層調(diào)用 tcp_output() 函數(shù),將 SYN 包輸出到接口。如圖 9 所示,soconnect 現(xiàn)在返回到connect() 函數(shù),并進(jìn)入睡眠狀態(tài)。客戶端上的套接字狀態(tài)現(xiàn)在是 SYN_SENT。接口層調(diào)用 if_output()(實(shí)際上是接口特定的輸出函數(shù)),將包發(fā)送到 n/w。

      目的地(服務(wù)器)上的接口接收傳入 SYN 包,將其放在 ipintrq 隊列中,并引發(fā)軟件中斷。包然后由調(diào)用 tcp_input 例程的ipintr() 獲取。tcp_input() 在 s/w 中斷時執(zhí)行,并從 ipintrq 拾取 SYN 包,對其進(jìn)行處理,并將部分完成的套接字連接放入完成的套接字隊列。服務(wù)器端的套接字狀態(tài)現(xiàn)在是 SYN_RCVD。每次處理后,tcp_input() 例程都調(diào)用 tcp_output()(如果需要將響應(yīng)套接字發(fā)送到另一端)。


      圖 9. 用于 SYN ACK 包的流序列
      點(diǎn)擊查看原始尺寸 

      處理 SYN 后,服務(wù)器使用 tcp_output ()ip_output () 和 if_output () 序列發(fā)送 SYN ACK 包。客戶端上的 n/w 接口接收此包,將其放在 ipintrq 中,并引發(fā) s/w 中斷。同樣,ipintr () 從 ipintrq 獲取該包,并將其傳遞到客戶端 TCP 堆棧上的tcp_input () 例程。包現(xiàn)在是經(jīng)過處理的,并調(diào)用了 soisconnected (),它喚醒連接調(diào)用??蛻舳松系奶捉幼譅顟B(tài)現(xiàn)在已建立。


      圖 10. 用于 ACK 包的流序列
      點(diǎn)擊查看原始尺寸 

      客戶端上的 tcp_input () 例程處理 SYN ACK 包,并調(diào)用 tcp_output () 將 ACK 包發(fā)回到服務(wù)器。服務(wù)器端上的 tcp_input () 處理此 ACK 包,并調(diào)用 soisconnected ()。此函數(shù)從未完成的套接字隊列移除套接字,并將其放入完成的套接字隊列,然后調(diào)用 Wakeup (),以喚醒 accept 調(diào)用。服務(wù)器端的套接字現(xiàn)在已建立。

      Shutdown

      shutdown (struct proc *p, struct shutdown_args *uap, int *retval);
                      Struct shutdown_args
                      {
                      int s;
                      int how;
                      }
                      

      在 shutdown 系統(tǒng)調(diào)用中:

      • s 是套接字描述符。
      • how 指定將關(guān)閉哪一部分連接。how 的值 0、1 和 2 分別指定關(guān)閉連接的讀取部分、寫入部分和同時關(guān)閉連接的讀取及寫入部分。

       

      shutdown 系統(tǒng)調(diào)用關(guān)閉連接的任意一端或兩端。如果需要關(guān)閉讀取部分,則會丟棄接收緩沖區(qū)中存在的任何數(shù)據(jù),并關(guān)閉該端的連接。對寫入部分,TCP 發(fā)送任何剩余的數(shù)據(jù),然后終止連接的寫入端。


      圖 11. 用于 shutdown 系統(tǒng)調(diào)用的調(diào)用序列
       

      如果需要關(guān)閉連接的讀取部分,則 soshutdown() 函數(shù)調(diào)用 sorflush()。sorflush() 標(biāo)記套接字以拒絕任何傳入的包,并釋放保存的任何系統(tǒng)資源。

      如果需要關(guān)閉連接的寫入部分,則調(diào)用 tcp_usrreq(),并將 PRU_SHUTDOWN 作為請求。PRU_SHUTDOWN 的切換實(shí)例根據(jù)當(dāng)前的狀態(tài)調(diào)用 tcp_usrclosed() 函數(shù),以更新套接字的狀態(tài)。TCP/IP 狀態(tài)圖表可以幫助了解套接字在任何給定的時間存在的不同狀態(tài)。如果從 tcp_usrclosed() 返回時需要發(fā)送 FIN,則調(diào)用 tcp_output() 將其發(fā)送到接口。

      Close

      soo_close(struct file *fp , struct proc *p);

      在 close 系統(tǒng)調(diào)用中:

      • fp 是指向文件結(jié)構(gòu)的指針。
      • p 是一個指向調(diào)用進(jìn)程的 proc 結(jié)構(gòu)的指針。

      close 系統(tǒng)調(diào)用可關(guān)閉或中止套接字上任何掛起的連接。

      soo_close() 僅調(diào)用 so_close() 函數(shù),該函數(shù)首先檢查要關(guān)閉的套接字是否為偵聽套接字(正在接收傳入連接的套接字)。如果是,則遍歷兩個套接字隊列,以檢查任何掛起的連接。對每個掛起的連接,將調(diào)用 soabort() 以發(fā)布 tcp_usrreq(),并將 PRU_ABORT 用作請求。此切換實(shí)例調(diào)用 tcp_drop() 以檢查套接字的狀態(tài)。

      如果狀態(tài)是 SYN_RCVD,則通過將狀態(tài)設(shè)置為 CLOSED 并調(diào)用 tcp_output() 發(fā)送 RST 段。tcp_close() 函數(shù)然后關(guān)閉套接字。tcp_close 函數(shù)更新路由度量結(jié)構(gòu)的三個變量,然后釋放套接字持有的資源。

      如果套接字不是偵聽套接字,則控制開始使用 soclose(),以檢查是否已存在附加到套接字的控制塊。如果不存在,則 sofree() 釋放套接字。如果存在,則調(diào)用具有 PRU_DETACH 的 tcp_usrreq() 將協(xié)議與套接字分離。PRU_DETACH 的切換實(shí)例調(diào)用tcp_disconnect(),以檢查連接狀態(tài)是否為 ESTABLISHED。如果不是,則 tcp_disconnect() 調(diào)用 tcp_close(),以釋放 Internet 和控制塊。否則,tcp_disconnect() 檢查延遲時間和延遲套接字選項。如果設(shè)置了該選項,并且延遲時間為零,則調(diào)用tcp_drop()。如果未設(shè)置,則調(diào)用 tcp_usrclosed(),以設(shè)置套接字的狀態(tài),并調(diào)用 tcp_output()(如果需要發(fā)送 FIN 段)。

      圖 12 顯示了 TCP 應(yīng)用程序發(fā)布 close 系統(tǒng)調(diào)用時發(fā)生的重要調(diào)用。


      圖 12. 用于 close 系統(tǒng)調(diào)用的調(diào)用序列
      點(diǎn)擊查看原始尺寸 

      Send

      sendmsg ( struct proc*p, struct sendmsg_args *uap, int retval);
                      struct sendmsg_args
                      {
                      int s;
                      caddr_t msg;
                      int flags;
                      };
                      

      在 send 系統(tǒng)調(diào)用中:

      • s 是套接字描述符。
      • msg 是指向 msghdr 結(jié)構(gòu)的指針。
      • flags 是控制信息。

      n/w 接口上有四個要發(fā)送數(shù)據(jù)的系統(tǒng)調(diào)用:write、writev、sendto 和 sendmsg。本文僅討論 sendmsg() 系統(tǒng)調(diào)用。所有的四個調(diào)用最終調(diào)用 sosend()。盡管 send(進(jìn)程調(diào)用的庫函數(shù))、sendto 和 sendmsg 系統(tǒng)調(diào)用僅可以對套接字描述符操作,但write 和 writev 系統(tǒng)調(diào)用則可以對任何類型的描述符操作。


      圖 13. 用于 sendmsg 的調(diào)用序列
      點(diǎn)擊查看原始尺寸 

      sendmsg 系統(tǒng)調(diào)用將從進(jìn)程發(fā)送的消息復(fù)制到內(nèi)核空間,并調(diào)用 sendit()。在 sendit() 中,將初始化一個結(jié)構(gòu),以便從進(jìn)程將輸出收集到內(nèi)核中的內(nèi)存緩沖區(qū)。還可以將地址和控制信息從進(jìn)程復(fù)制到內(nèi)核,然后調(diào)用 sosend(),以執(zhí)行以下四項任務(wù):

      • 基于 sendit() 函數(shù)傳遞的值初始化各種參數(shù)。
      • 驗(yàn)證套接字的條件和連接的狀態(tài),并確定傳遞消息和報告錯誤所需的空間。
      • 分配內(nèi)存并從進(jìn)程復(fù)制數(shù)據(jù)。
      • 使協(xié)議特定的調(diào)用將數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)。

       

      然后調(diào)用 tcp_usrreq(),并根據(jù)進(jìn)程指定的標(biāo)志,控制切換到 PRU_SEND 或 PRU_SENDOOB(以發(fā)送帶區(qū)外數(shù)據(jù))。對于 PRU_SENDOOB,發(fā)送緩沖區(qū)大小可以超過 512 字節(jié),將釋放任何分配的內(nèi)存并中斷控制。否則,sbappend() 和 tcp_output()函數(shù)由 PRU_SEND 和 PRU_SENDOOB 調(diào)用。sbappend() 在發(fā)送緩沖區(qū)的末尾添加數(shù)據(jù),并且 tcp_output() 將該段發(fā)送到接口。

      Receive

      recvmsg(struct proc *p, struct recvmsg_args *uap , int *retval);
                      struct recvmsg_args
                      {
                      int s,
                      struct msghdr *msg,
                      int flags,
                      };
                      

      在 receive 系統(tǒng)調(diào)用中:

      • s 是套接字描述符。
      • msg 是指向 msghdr 結(jié)構(gòu)的指針。
      • flags 指定控制信息。

      有四個系統(tǒng)調(diào)用可以用于從連接接收數(shù)據(jù):read、readv、recvfrom 和 recvmsg。盡管 recv(進(jìn)程使用的庫函數(shù))、recvfrom和 recvmsg 僅可以對套接字描述符操作,但 read 和 readv 可以對任何種類的描述符操作。所有的 read 系統(tǒng)調(diào)用最終調(diào)用soreceive()。

      圖 14 顯示了用于 recvmsg 系統(tǒng)調(diào)用的調(diào)用序列。recvmsg() 和 recvit() 函數(shù)初始化各種數(shù)組和結(jié)構(gòu),將接收的數(shù)據(jù)從內(nèi)核發(fā)送到進(jìn)程。recvit() 調(diào)用 soreceive(),以便將接收的數(shù)據(jù)從套接字緩沖區(qū)傳輸?shù)浇邮站彌_區(qū)進(jìn)程。soreceive() 函數(shù)執(zhí)行各種檢查,如:

      • 是否設(shè)置了 MSG_OOB 標(biāo)志。
      • 進(jìn)程是否嘗試接收數(shù)據(jù)。
      • 是否應(yīng)該阻塞,直到足夠的數(shù)據(jù)到達(dá)。
      • 將讀取數(shù)據(jù)傳輸?shù)竭M(jìn)程。
      • 檢查數(shù)據(jù)是帶區(qū)外數(shù)據(jù)還是常規(guī)數(shù)據(jù),并進(jìn)行相應(yīng)的處理。
      • 當(dāng)數(shù)據(jù)接收完成后通知協(xié)議。

       


      圖 14. 用于 recvmsg 的調(diào)用序列
      點(diǎn)擊查看原始尺寸

      當(dāng)設(shè)置 MSG_OOB 標(biāo)志時或數(shù)據(jù)接收完成后,soreceive() 函數(shù)進(jìn)行與協(xié)議相關(guān)的請求。在接收帶區(qū)外數(shù)據(jù)的情況下,協(xié)議層檢查不同的條件,以驗(yàn)證接收的數(shù)據(jù)是否為帶區(qū)外數(shù)據(jù),然后將其返回到套接字層。在后一種情況中,協(xié)議層調(diào)用 tcp_output(),將窗口更新段發(fā)送到網(wǎng)絡(luò)。它通知另一端任何空間都可用于接收數(shù)據(jù)。

      結(jié)束語

      在本文中,您學(xué)習(xí)了觸發(fā)低級別調(diào)用以完成某些任務(wù)的最重要的 TCP 函數(shù)調(diào)用。圖中的調(diào)用序列顯示了內(nèi)核級 TCP 調(diào)用的簡要概述。本文是了解 FreeBSD TCP/IP 堆棧組織的很好起點(diǎn)。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多