通訊端與 BSD 通訊端 API(socket and BSD socket API)
/ BSD -> BEE-ESS-DEE, socket -> SOCK-it /
把通訊端想成你的程式插上去以連到網路的牆上插座。一旦插好,你的程式碼就不必直接處理電纜、路由器或 IP 封包——它只是透過那一個插座,讀進進來的位元組、寫出要送出的位元組。通訊端是作業系統替一段網路對話的一端所提供的把手:一個你的程式擁有、用來收送資料的端點。
具體來說,通訊端由一個系統呼叫建立,回傳的是一個檔案描述符(file descriptor)——就是作業系統替已開啟檔案給你的那種小整數。這是刻意的:設計者讓網路看起來像一個檔案,好讓你能用你早已熟悉的 read() 與 write() 來操作它。BSD 通訊端 API(誕生於 1980 年代初的 Berkeley Unix)就是建立並操作這些端點的那一小組系統呼叫:socket()、bind()、listen()、accept()、connect()、send()、recv()、close(),以及幾個輔助函式。幾乎每個作業系統——Linux、macOS、Windows(以 Winsock 之名)——都提供幾乎相同的呼叫,這正是為什麼通訊端程式碼如此可攜。
為何重要:通訊端是你的程式與網路相遇之處,而 BSD API 則是這場相遇的通用詞彙。學會這寥寥幾個呼叫,你就能在幾乎任何機器上寫出客戶端與伺服器。關鍵的心智轉換是:通訊端不過是一個另一端接著網路的檔案描述符——所以你辛苦習得的關於檔案描述符、阻塞與部分讀取的知識,在這裡都能直接套用。
int fd = socket(AF_INET, SOCK_STREAM, 0); 建立一個 TCP 通訊端。回傳值 fd 是一個檔案描述符,也許是 3——從此之後你可以對它做 read(fd, ...)、write(fd, ...),或網路專屬的 recv(fd, ...) 與 send(fd, ...),用完再 close(fd)。
socket() 回傳一個檔案描述符;網路如今不過是另一個你讀寫的對象。
通訊端是由檔案描述符所指涉的核心物件,不是一塊硬體,也不等同於連接埠。一個行程可以同時持有許多通訊端,正如它能持有許多已開啟的檔案一樣。