16.1 引言
*進程能夠通過通訊端網路IPC介面和其他進程通訊。通過該介面,其他進程運行位置是透明的,它們可以在同一台電腦上也可以在不同的電腦上。實際上,這正是通訊端的目標之一:同樣的介面既可以用於電腦間通訊又可以用於電腦內通訊
*16.2 通訊端描述符
*要建立一個通訊端,可以調用socket函數
int socket(int domain, int type, int protocol);
*通訊端通訊是雙向的,可以採用函數shutdown來禁止通訊端上的輸入/輸出
int shutdown(int sockfd, int how);
16.3 定址
*確定一個目標通訊進程使用進程標識的方式,進程的標識有兩個部分:電腦的網路地址可以協助標識電腦網路上想與之通訊的電腦,而服務可以協助標識電腦上的特定的進程
*如果處理器架構支援大端(big-endian)位元組序,那麼最大位元組地址對應於數字最低有效位元組(LSB)上;小端(little-endian)位元組序則相反:數字最低位元組對應於最小位元組地址
*通訊端可以自由地添加額外的成員並且定義sa_data成員的大小
*在Linux中,通訊端地址結構定義如下:
struct sockaddr{
sa_family_tsa_family;
charsa_data[14];
}
*在FreeBSD中,通訊端地址結構定義如下:
struct sockaddr{
unsigned charsa_len;
sa_family_tsa_family;
charsa_data[14];
}
*在IPv4網際網路(AF_INET)中,通訊端地址用結構sockaddr_in表示
*可以用bind函數將地址綁定到一個通訊端
16.4 建立串連
*可以用connect建立一個串連
*伺服器調用listen來宣告可以接受串連請求
*使用函數accept獲得串連請求並建立串連。函數accept所返回的檔案描述符是通訊端描述符,該描述符串連到調用connect的用戶端
16.5 資料轉送
*三個函數用來發送資料,三個用來接收資料
*最簡單的是send,它和write很像,但是可以指定標識來改變處理傳輸資料的方式
*函數sendto和send很類似。區別在於sendto允許在不需連線的通訊端上制定一個目標地址
*可以使用不止一個的選擇來通過通訊端發送資料。可以調用帶有msghdr結構的sendmsg來指定多重緩衝區傳輸資料,這和writev很相像
*函數recv和read很像,但是允許指定選項來控制如何接收資料
*如果有興趣定位寄件者,可以使用recvfrom來得到資料寄件者的源地址
*為了將接收到的資料送入多個緩衝區(類似於readv),或者想接收輔助資料,可以使用recvmsg
16.6 通訊端選項
*通訊端機制提供兩個通訊端選項介面來控制通訊端行為。一個介面用來設定選項,另一個介面允許查詢一個選項的狀態。可以擷取或設定三種選項:
(1)通用選項,工作在所有通訊端類型上
(2)在通訊端層次管理的選項,但是依賴於下層協議的支援
(3)特定於某協議的選項,為每個協議所專屬
*可以採用setsockopt函數來設定通訊端選項
*使用getsockopt函數來發現選項的當前值
int getsockopt(int sockfd, int level, int option, void *restrict val, socklen_t *resctrict lenp)
注意到參數lenp是一個指向整數的指標。在調用getsockopt之前,設定該整數為複製選項緩衝區的大小。如果實際的尺寸大於此值,選項會被截斷而不報錯;如果實際尺寸正好等於或者小於此值,那麼返回時將此值更新為實際尺寸
16.7 帶外資料
*帶外資料(Out-of-band data)是一些通訊協定所支援的可選特徵,允許更高優先順序的資料比普通資料優先傳輸。即使傳輸隊列已經有資料,帶外資料先行傳輸。TCP支援帶外資料,但是UDP不支援
*TCP支援緊急標記(urgent mark)的概念:在普通資料流中緊急資料所在的位置
16.8 非阻塞和非同步I/O
*通常,recv函數沒有資料可用會阻塞等待。同樣地,當通訊端輸出隊列沒有足夠空間來發送訊息時函數send會阻塞。在通訊端非阻塞模式下,行為會改變。在這種情況下,這些函數不會阻塞而是失敗,設定errno為EWOULDBLOCK或者EAGAIN。當這些發生時,可以使用poll或select來判斷何時能接收或傳輸資料