小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

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

引言

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


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

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


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

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

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

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

每個(gè)套接字具有一個(gè)套接字隊(duì)列,并且每個(gè)接口具有一個(gè)用于數(shù)據(jù)通信的接口隊(duì)列。不過(guò),對(duì)于整個(gè)協(xié)議層,只有一個(gè)稱為 IP 輸入隊(duì)列的協(xié)議隊(duì)列。接口層通過(guò)此 IP 輸入隊(duì)列將數(shù)據(jù)輸入到協(xié)議層。協(xié)議層使用相應(yīng)的接口隊(duì)列將數(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 是一個(gè)指針,指向進(jìn)行 socket 調(diào)用的進(jìn)程的 proc 結(jié)構(gòu)。
  • uap 是一個(gè)指向 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)用通過(guò)分配新的描述符創(chuàng)建新的套接字。將新的描述符返回到調(diào)用進(jìn)程。任何后續(xù)的系統(tǒng)調(diào)用都使用創(chuàng)建的套接字標(biāo)識(shí)。socket 系統(tǒng)調(diào)用還向創(chuàng)建的套接字描述符分配協(xié)議。

domain、type 和 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é)議特定的請(qǐng)求。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)識(shí)請(qǐng)求。本例中為 PRU_ATTACH。
  • m0、m1 和 m2 是指向 mbuf 結(jié)構(gòu)的指針。值因請(qǐng)求而異。

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

tcp_usrreq() 函數(shù)調(diào)用 tcp_attach( ),以處理 PRU_ATTACH 請(qǐng)求。要分配 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 定時(shí)器變量,并且控制返回到 tcp_attach()?,F(xiàn)在套接字狀態(tài)初始化為 CLOSED。在返回到 tcp_usrreq 函數(shù)時(shí),創(chuàng)建套接字描述符,以指向套接字的 TCP 控制塊。

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

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)。對(duì)于客戶端進(jìn)程,發(fā)布 bind 調(diào)用不是強(qiáng)制的。當(dāng)客戶端進(jìn)程發(fā)布 connect 系統(tǒng)調(diào)用時(shí),內(nèi)核負(fù)責(zé)執(zhí)行隱式綁定。服務(wù)器進(jìn)程接受連接或啟動(dòng)與客戶端的通信之前,發(fā)布顯式綁定請(qǐng)求通常是必需的。

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

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


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

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

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

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

如果端口上已存在偵聽(tīng)的套接字,則將套接字的狀態(tài)更改為 LISTEN。通常,所有的服務(wù)器進(jìn)程都偵聽(tīng)眾所周知的端口號(hào)。很少調(diào)用in_pcbbind 來(lái)執(zhí)行服務(wù)器進(jìn)程的隱式綁定。圖 5 顯示了偵聽(tīng)的調(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ù)),它包含外來(lái)主機(jī)的網(wǎng)絡(luò)傳輸?shù)刂贰?/li>
  • anamelen 是 name 緩沖區(qū)的大小。

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


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

accept 調(diào)用首先驗(yàn)證參數(shù),并等待要到達(dá)的連接請(qǐng)求。在此之前,函數(shù)在 while 循環(huán)中阻塞。新的連接到達(dá)后,協(xié)議層喚醒服務(wù)器進(jìn)程。Accept 然后檢查函數(shù)阻塞時(shí)發(fā)生的任何套接字錯(cuò)誤。如果存在任何套接字錯(cuò)誤,則函數(shù)返回,并繼續(xù)從隊(duì)列拾取新的連接并調(diào)用soaccept。在 soaccept() 中調(diào)用 tcp_usrreq () 函數(shù),并將請(qǐng)求作為 PRU_ACCEPT。tcp_usrreq 函數(shù)中的切換調(diào)用in_setpeeraddr(),后者從協(xié)議控制塊復(fù)制外來(lái) IP 地址和外來(lái)端口號(hào),并將其返回到服務(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 是指向具有外來(lái) IP/端口地址對(duì)的緩沖區(qū)的指針。
  • namelen 是緩沖區(qū)的長(zhǎng)度。

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

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

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

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


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

3 向 TCP 握手

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


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

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

目的地(服務(wù)器)上的接口接收傳入 SYN 包,將其放在 ipintrq 隊(duì)列中,并引發(fā)軟件中斷。包然后由調(diào)用 tcp_input 例程的ipintr() 獲取。tcp_input() 在 s/w 中斷時(shí)執(zhí)行,并從 ipintrq 拾取 SYN 包,對(duì)其進(jìn)行處理,并將部分完成的套接字連接放入完成的套接字隊(duì)列。服務(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)過(guò)處理的,并調(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ù)從未完成的套接字隊(duì)列移除套接字,并將其放入完成的套接字隊(duì)列,然后調(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)閉連接的讀取部分、寫(xiě)入部分和同時(shí)關(guān)閉連接的讀取及寫(xiě)入部分。

 

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


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

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

如果需要關(guān)閉連接的寫(xiě)入部分,則調(diào)用 tcp_usrreq(),并將 PRU_SHUTDOWN 作為請(qǐng)求。PRU_SHUTDOWN 的切換實(shí)例根據(jù)當(dāng)前的狀態(tài)調(diào)用 tcp_usrclosed() 函數(shù),以更新套接字的狀態(tài)。TCP/IP 狀態(tài)圖表可以幫助了解套接字在任何給定的時(shí)間存在的不同狀態(tài)。如果從 tcp_usrclosed() 返回時(shí)需要發(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 是一個(gè)指向調(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)閉的套接字是否為偵聽(tīng)套接字(正在接收傳入連接的套接字)。如果是,則遍歷兩個(gè)套接字隊(duì)列,以檢查任何掛起的連接。對(duì)每個(gè)掛起的連接,將調(diào)用 soabort() 以發(fā)布 tcp_usrreq(),并將 PRU_ABORT 用作請(qǐng)求。此切換實(shí)例調(diào)用 tcp_drop() 以檢查套接字的狀態(tài)。

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

如果套接字不是偵聽(tīng)套接字,則控制開(kāi)始使用 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í)間和延遲套接字選項(xiàng)。如果設(shè)置了該選項(xiàng),并且延遲時(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)用時(shí)發(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 接口上有四個(gè)要發(fā)送數(shù)據(jù)的系統(tǒng)調(diào)用:write、writev、sendto 和 sendmsg。本文僅討論 sendmsg() 系統(tǒng)調(diào)用。所有的四個(gè)調(diào)用最終調(diào)用 sosend()。盡管 send(進(jìn)程調(diào)用的庫(kù)函數(shù))、sendto 和 sendmsg 系統(tǒng)調(diào)用僅可以對(duì)套接字描述符操作,但write 和 writev 系統(tǒng)調(diào)用則可以對(duì)任何類型的描述符操作。


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

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

  • 基于 sendit() 函數(shù)傳遞的值初始化各種參數(shù)。
  • 驗(yàn)證套接字的條件和連接的狀態(tài),并確定傳遞消息和報(bào)告錯(cuò)誤所需的空間。
  • 分配內(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ù))。對(duì)于 PRU_SENDOOB,發(fā)送緩沖區(qū)大小可以超過(guò) 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 指定控制信息。

有四個(gè)系統(tǒng)調(diào)用可以用于從連接接收數(shù)據(jù):read、readvrecvfrom 和 recvmsg。盡管 recv(進(jìn)程使用的庫(kù)函數(shù))、recvfrom和 recvmsg 僅可以對(duì)套接字描述符操作,但 read 和 readv 可以對(duì)任何種類的描述符操作。所有的 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í)或數(shù)據(jù)接收完成后,soreceive() 函數(shù)進(jìn)行與協(xié)議相關(guān)的請(qǐng)求。在接收帶區(qū)外數(shù)據(jù)的情況下,協(xié)議層檢查不同的條件,以驗(yàn)證接收的數(shù)據(jù)是否為帶區(qū)外數(shù)據(jù),然后將其返回到套接字層。在后一種情況中,協(xié)議層調(diào)用 tcp_output(),將窗口更新段發(fā)送到網(wǎng)絡(luò)。它通知另一端任何空間都可用于接收數(shù)據(jù)。

結(jié)束語(yǔ)

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

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多