1. 程式人生 > >UNP-套接字選項

UNP-套接字選項

unp 其他 等待 兩個 3.1 ons 都是 構造 nbsp

第7章 套接字選項

7.1 獲取和設置選項

int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen);
int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t optlen);
// 成功0 ,錯誤-1

其中optval是0或是非0值表示是否開啟,其他結構提表示設置值

7.2 level:SOL_SOCKET

7.2.1 SO_BROADCAST

optval:int類型

是否允許廣播

不能再基於連接的傳輸協議和點對點鏈路上進行廣播

應用程序在發送廣播數據包之前必須設置本套接字選項,能夠有效的防止一個進程在其應用程序本沒有設計成可廣播的時候,發送廣播數據報.

如果沒有設置SO_BROADCAST選項,返回EACCES錯誤

7.2.2 SO_DONTROUTE

int

套接字外出分組逃過底層協議的正常路由選路.

通常是在一個子網直連網絡上.

如果不是在直連網絡上,而又設置了該選項,返回ENETUNREACH錯誤

這個選項和send,`sendto,sendmsg使用了MSG_DONTROUTE選項是相同的結果.

7.2.3 SO_ERROR

int

當套接字出現錯誤的時候,使用該選項,獲取錯誤值,內核so_error變量

當套接字出現錯誤的時候,則該套接字為待處理錯誤:

  • 多路復用下,該套接字可讀可寫

  • 信號驅動下,SIGIO信號

當read套接字的時如果沒有讀到數據,同時so_error非0,則read返回so_error的值(而非0),同時內核重置so_error

write時,如果so_error非0,則返回so_error,同時內核重置so_error

so_error的值為標準的error中的一個.

7.2.4 SO_KEEPALIVE

int

保活選項.

Tcp定時給對端發送保活探測分節:

  • 對端回復ACK,表示連接正常

  • 對端RST回復,表示對端已經崩潰重啟

    so_error為ECONNRESET套接字本身被關閉

  • 沒有相應,超時後放棄,

    so_error為ETIMEOUT

    如果收到了ICMP主機不可達的報文,表示對端主機沒有崩潰只是不可達,此時so_error為EHOSTUNREACH

    這種情況是可能為對端主機崩潰,或是網絡故障.

如果想要更改保活探測時間,不能從這兩個函數中修改,應該修改系統的參數,此時對所有套接字起效(修改時間時).

7.2.5 SO_LINGER


struct linger
{
int l_onoff; // 0 關閉,非0,開啟
int l_linger; //單位秒
};

表示,在close套接字的時候,在發送緩沖區的數據,如果和處理

  1. 00

    表示關閉,此時執行默認操作,close立即返回發送緩沖區的數據被發送出去,發送完畢後發送FIN分節關閉套接字(套接字引用計數為0時,也就是只有這個描述符關聯了這個套接字)

    第一個為0時,忽略第二個值

  2. 10

    開啟了選項,同時不等待數據發送完畢

    close直接返回,發送RST分節,套接字狀態直接到CLOSED,不進入TIME_WAIT階段

  3. 1n

    開啟選項,同時設置等待事件

    close阻塞直到發送完畢正常返回,如果指定時間內沒有發送完,那麽close返回EWOULDBLOCK錯誤.數據被丟棄

7.2.5 SO_RCVBUF SO_SNDBUF

int

每個套接字都有發送和接受緩沖區.

TCP的SO_RCVBUF是窗口通告大小,udp的則是接收到的數據不能放到緩沖區就丟棄

TCP連接在三次握手時交換窗口大小,因此需要在connect和listen之前設置該選項

TCP套接字緩沖區至少為MSS的四倍,而且為雙數倍,原因在於,tcp雙工,在一個管道中發送的包數量應該等於相反方向管道中ACK的數量,那麽發送緩沖區的MSS就是雙數倍大小,存在2n個待確認的包.

7.2.6 SO_RCVLOWAT SO_SNDLOWAT

IO復用用的何時需要喚醒一個套接字可讀和可寫

SO_RCVLOWAT一般都為1

SO_SNDLOWAT:TCP為2048.udp因為發送不需要保存副本,因此只要只要發送緩沖區大小大於套接字低水位標記,udp總是可寫

7.2.7 SO_REUSEADDR

int

linux中,只要一個端口正在使用,也就是說端口上有鏈接,那麽就不能在該端口上啟動另一個連接

S_REUSEADDR:

  1. 允許一個監聽服務器綁定在一個已經存在連接的本地端口上(此時該鏈接不是監聽連接,而一個服務連接)

    主要在於讓bind成功

  2. 同一端口啟動同一服務器的多個實例,只要ip不同即可

  3. 允許單進程綁定同一端口到多個套接字上,只要本地ip地址不同即可

  4. 協議允許的話,相同的ip和端口可已綁定在同一套接字上

這裏的套接字都是只外出,監聽的套接字,也就是說,用了同一臺電腦的同一協議端口,(可能)同一ip地址

需要在bind之前設置

對於bind到同一端口的不同ip的進程,數據包如何分配的問題,是更加通用的優先獲得.最後再分給最通用的

7.2.8 SO_REUSEPORT

int

  1. 允許重復ip和端口綁定

    但是必須這些套接字都開啟了該選項

  2. 如果是一個多播地址,那麽SO_REUSEADDR == SO_REUSEPORT

7.2.9 SO_TYPE

int

返回套接字類型

7.3 level:IPPEOTO_IP

ipv4套接字選項

7.3.1 IP_HDRINCL

int

應用於原始套接字.是否需要我們手動構造ip頭部,開啟表示我們手動構造.

開啟是內核為我們構造的是:

  1. ip首部校驗和

  2. ip標識字段為0,內核為構造

  3. ip源地址為INADDR_ANY,內核填充

  4. 設置的ip選項,內核填充

諸暨序和網絡序手動確定

7.3.2 IP_OPTIONS

int

是否允許設置ip選項

7.3.3 IP_TTL

int

設置TTL

7.4 level:IPPROTO_TCP

7.4.1 TCP_MAXSEG

int

設置TCP連接最大分節大小MSS.

該選項必須在connect之前,因為MSS是在SYN中告訴對端

7.4.2 TCP_NODELAY

int

是否禁用nagle算法.

在接收到ACK之前,那麽任何小於MSS的報文將被組合為一個MSS,在收到ACK後發送,因此是一種等停式的傳輸.

nagle與延時ACK構成短暫的死鎖.

SO_REUSEADDR和SO_REUSEPORT區別

SO_REUSEADDR主要改變了系統對待通配符IP地址沖突的方式。

如果不用SO_REUSEADDR的話,如果我們將socketA綁定到0.0.0.0:21,那麽任何將本機其他socket綁定到端口21的舉動(如綁定到192.168.1.1:21)都會導致EADDRINUSE錯誤。因為0.0.0.0是一個通配符IP地址,意味著任意一個IP地址,所以任何其他本機上的IP地址都被系統認為已被占用。如果設置了SO_REUSEADDR選項,因為0.0.0.0:21192.168.1.1:21並不是完全相同的地址端口對(其中一個是通配符IP地址,另一個是一個本機的具體IP地址),所以這樣的綁定是可以成功的。需要註意的是,無論socketAsocketB初始化的順序如何,只要後一個設置了SO_REUSEADDR,綁定都會成功;而只要沒有設置SO_REUSEADDR,綁定都不會成功。

SO_REUSEPORT

基本上來說,SO_REUSEPORT允許我們將任意數目的socket綁定到完全相同的源地址端口對上,只要所有之前綁定的socket都設置了SO_REUSEPORT選項。如果第一個綁定在該地址端口對上的socket沒有設置SO_REUSEPORT,無論之後的socket是否設置SO_REUSEPORT,其都無法綁定在與這個地址端口完全相同的地址上。除非第一個綁定在這個地址端口對上的socket釋放了這個綁定關系。與SO_REUSEADDR不同的是 ,處理SO_REUSEPORT的代碼不僅會檢查當前嘗試綁定的socket的SO_REUSEPORT,而且也會檢查之前已綁定了當前嘗試綁定的地址端口對的socket的SO_REUSEPORT選項。如果當前一個socket沒有設置SO_REUSEPORT已經處於TIME_WAIT階段,而這個設置了SO_REUSEPORT選項的新socket嘗試綁定到當前地址,這個綁定操作也會失敗。

UNP-套接字選項