套接字緩沖區相關
書里面講了三種方式(TCP,UDP,SCTP)的發送相關,但是原理基本是相同的,只是根據不同協議的特點有些變化.下面
以TCP為例,試着描述一下這個過程.
TCP緩沖區
每一個TCP套接字都有一個發送緩沖區,這個緩沖區是在內核中的.當我們調用write將數據寫入套接字的時候,數據被傳入
內核,放入套接字發送緩沖區(大小可以由SO_SNDBUF來設定).如果緩沖區已滿,那么write函數將被阻塞,進程被投入睡眠狀態.
直到數據全部被傳入內核的套接字緩沖區中.需要注意的是,當write返回的時候並不代表對端已經收到了這些數據,只是說明這些
數據被寫到了內核中的緩沖區里面.
當數據到達內核中以后,內核中的TCP程序會對其進行一次加工,將數據以MSS(maximum segment size)大小分塊,並給每個數據塊
安上一個TCP首部,隨后發給IP程序.
IP程序可能會對數據進行進一步的分片,取決於MSS的大小.有的系統在實現中使用了路徑MTU發現機制,會盡量減少分片的情況.通用的
做法就是給數據包加上IP頭,按照其目的IP地址查找路由表確定網絡接口,然后傳遞給數據鏈路層.
數據鏈路層中會維護一個隊列,如果隊列已滿,則會沿協議棧返回一個錯誤,最終由TCP捕獲這個錯誤,並重傳該數據.
TCP緩沖區一個很重要的問題就是何時從套接字緩沖區中將已發送的數據丟棄.我們知道TCP是一個可靠的傳輸協議,所以TCP實現了關於確認數據
到達的相關機制,即當對端確認數據到達的ack返回時,則認定我們發送的數據已經被對方接受.此時內核中的套接字緩沖區才會將數據刪除.在確認的
ack到達之前,內核的套接字緩沖區中會為數據維護一個副本,防止數據由於損壞或者丟失造成重傳的時候內核已經將其刪除了.
UDP緩沖區
UDP套接字的緩沖機制就不在詳述,因為UDP是一個不可靠協議,所以它並不會維護一個真正的套接字緩沖區,而是直接沿協議棧向下傳遞,被復制到某種
格式的內核緩沖區當中.但是如果UDP打算傳送一個大於"緩沖區大小"(即SO_SNDBUF的大小)的數據報時,則會返回一個EMSGSIZE的錯誤.它經過內核中
的UDP和IP程序,並被發送到數據鏈路層的緩沖隊列當中,如果隊列已滿則返回一個ENOBUFS的錯誤(有的系統並不會返回錯誤).可以看到,UDP並不會為
用戶程序維護一個狀態.