這幾個屬性是從監聽套接字繼承的,要想設置已鏈接套接字的這些屬性,須要在監聽套接字上設置。linux
若是設置了這個選項,當2小時內套接字的任一方向都沒有數據交換時,TCP會自動發送一個探活數據包(keep-alive probe),接下來會有幾種可能:算法
這個選項表示如何關閉面向鏈接的協議,默認是調用close
時當即返回,但若是發送緩衝區有殘留的數據,會嘗試將其發送給對端。服務器
設置時經過如下結構體來控制參數:網絡
struct linger {
int l_onoff; /* option on/off */
int l_linger; /* linger time, 單位爲秒*/
};
複製代碼
l_onoff
爲0時表示選項關閉,l_linger
的值被忽略,調用close
時會馬上返回l_onoff
爲非0而l_linger
爲0時,調用close
關閉某個鏈接時TCP會停止該鏈接,即丟棄發送緩衝區的全部數據並向對端發送一個RST,而不是進行正常的四次揮手。這樣可以避免TCP的TIME_WAIT狀態,可是也可能出現2MSL內建立出該鏈接的化身的狀況,致使來自剛纔被終止的鏈接上的舊的數據被髮送到新的化身上。l_onoff
爲非0並且l_linger
也爲非0時,關閉套接字時內核將會拖延一段時間。若是此時發送緩衝區中有數據,進程將會進入睡眠,直到:(a) 全部數據都已發送並被對端確認;(b) 拖延時間到。若是套接字被設置爲非阻塞型,close
會當即返回,即便拖延時間爲非0的狀況也是。在使用SO_LINGER選項時,應該檢查close
的返回值,若是在數據發送完並被確認前拖延時間到的話,close
會返回EWOULDBLOCK,且發送緩衝區的數據都會被丟棄。SO_REUSEADDR
容許一個監聽套接字綁定到其衆所周知端口,即便之前創建的將該端口做爲本地端口的鏈接仍存在。好比監聽的進程中途關閉了但其創建的子進程和鏈接仍存在,這時監聽進程重啓時嘗試從新綁定端口時須要指定了SO_REUSEADDR
才行,不然會綁定失敗。獲取或設置TCP最大分節大小(MSS),表示TCP可以發送的最大數據量,一般由對端的SYN分節指定,除非咱們選擇一個更小的值。若是在鏈接創建以前查詢,返回的是默認值。異步
開啓該選項將禁用Nagle算法,默認狀況其是啓用的。nagle算法能夠減小大量小的數據包在網絡中傳輸的狀況。函數
linux2.4以後的版本才支持選項,開啓該選項將啓用cork算法,默認是禁用的。cork選項能夠禁止小的數據包在網絡中傳輸。性能
fcntl顧名思義,能夠對描述符進行各類控制操做,主要經過cmd和arg兩個參數來控制。大數據
int fcntl(int fd, int cmd, .../* args */) 複製代碼
可選的cmd有:spa
F_SETFL
設置flagF_GETFL
獲取flagF_SETOWN
設置套接字屬主F_GETOWN
獲取套接字屬主使用方式:指針
int flags;
//先獲取當前flags
if ((flags = fcntl(fd, F_GETFL, 0)) < 0) {
//error
}
//增長O_NONBLOCK選項
flags |= O_NONBLOCK;
//設置flags
if ((flags = fcntl(fd, F_SETFL, flag)) < 0) {
//error
}
//設置flags
if (fcntl(fd, F_SETFL, flags) < 0) {
//error
}
//關閉O_NONBLOCK選項
flags &= ~O_NONBLOCK
//設置flags
if (fcntl(fd, F_SETFL, flags) < 0) {
//error
}
複製代碼
在使用fcntl
時,必須先獲取當前的標誌,而後與新的標誌或以後再設置標誌,不然會清除描述符的其餘標誌。
ssize_t sendto(int fd, const void *buff, size_t nbytes,
int flags, const struct sockaddr *to, socklen_t *addrlen);
ssize_t recvfrom(int fd, void *buff, size_t nbytes,
int flags, struct sockaddr *from, socklen_t *addrlen);
複製代碼
函數返回發送或者接收的字節數,最後兩個參數指定了對端地址。若是recvfrom的後兩個參數是空指針,則表示不關心數據發送者的協議地址。
在一個UDP套接字上調用sendto
時,若是對端不可用,對端會返回一個ICMP消息(好比"port unreachable"),但這個錯誤不會返回給應用程序,sendto
仍可以正常返回。
咱們稱這裏的這個ICMP錯誤爲異步錯誤,這個錯誤由sendto
觸發,可是sendto
自己卻成功返回;緣由是sendto
的成功僅表示在網絡接口輸出隊列中具有足夠的空間存放sendto
造成的IP數據報,而真正的錯誤在隨後實際發出數據包的時候才發生,因此咱們稱這個錯誤是異步的。
對於異步錯誤,處理的基本規則是:對於一個UDP套接字,由它引起的異步錯誤不會返回給它,除非它已鏈接。這裏的已鏈接指的是成功調用了connect
函數。爲何這麼規定呢?由於一個UDP套接字可能會往多個對端發送和讀取數據,而sendto
和recvfrom
只能返回單純的errno
,不能返回對端的ip和端口號信息。因此咱們決定:只有在UDP已經只綁定到一個對端時,這些異步錯誤才返回給進程。
除非udp套接字事先成功調用了connect
,不然sendto
和recvfrom
發生的異常不會返回給應用程序。
對一個UDP套接字調用connect
函數並不會像TCP套接字那樣進行三次握手,而是先檢查傳入的地址是否合法(是否可達等)而後保存ip和port到傳入的套接字地址結構體中,接着直接返回。
一旦一個UDP套接字已鏈接,會發生三個變化:
sendto
時不能再指定最後兩個參數(目標地址和地址長度),必須設置爲空指針;或者改用write
或者send
recvfrom
時不能再指定最後兩個參數(目標地址和地址長度),必須設置爲空指針;或者改用read
/recv
/recvmsg
和TCP套接字不一樣,UDP套接字能夠屢次調用connect
函數,經過這樣作能夠達到兩個目的:
AF_UNSPEC
便可)對於未鏈接的UDP套接字,每次調用sendto
函數時都會隱式地進行套接字鏈接和斷開鏈接;因此若是肯定UDP套接字要發送的對端只有一個時,能夠經過顯式鏈接來提升效率。