理解 Socket 首先要熟悉 TCP/IP 協(xié)議簇,TCP/IP(Transmission Control Protocol/Internet Protocol,傳輸控制協(xié)議/網(wǎng)間協(xié)議)定義了主機(jī)如何接入Internet 及數(shù)據(jù)如何傳輸?shù)臉?biāo)準(zhǔn)。

TCP/IP 是 TCP 和 IP 協(xié)議的合稱,但實(shí)際上 TCP/IP 協(xié)議是指 Internet 整個(gè) TCP/IP 協(xié)議簇,不同于 ISO 七層模型的分層,TCP/IP 協(xié)議參考模型把所有 TCP/IP 系列協(xié)議歸納抽象為4層:
- 應(yīng)用層 協(xié)議:TFTP、HTTP、SNMP、FTP、SMTP、DNS、Telnet...
- 傳輸層 協(xié)議:TCP、UDP
- 網(wǎng)路層 協(xié)議:IP、ICMP、OSPF、EIGRP、IGMP
- 數(shù)據(jù)鏈路層 協(xié)議:SLIP、CSLIP、PPP、MTU
TCP/IP是一種工業(yè)標(biāo)準(zhǔn)的協(xié)議集,為廣域網(wǎng) WAN 而設(shè)計(jì)。每一個(gè)抽象層建立在低一層所提供的服務(wù)上,并為高一層提供服務(wù)。
在 TCP/IP 協(xié)議中兩個(gè) Internet 主機(jī)通過路由器和對(duì)應(yīng)的層連接,各主機(jī)上得應(yīng)用通過數(shù)據(jù)通道相互執(zhí)行讀取操作。

本地進(jìn)程間通信
”進(jìn)程通信“的概念最初來源于單機(jī)系統(tǒng),由于每個(gè)進(jìn)程都在自己地址范圍內(nèi)運(yùn)行,為保證兩個(gè)相互通信的進(jìn)程之間互不干擾又協(xié)調(diào)一致的工作,操作系統(tǒng)為進(jìn)程通信提供了相應(yīng)的設(shè)施。
本地進(jìn)程間通信IPC方式
- 消息傳遞:管道、FIFO、消息隊(duì)列
- 同步:互斥量、條件變量、讀寫鎖、文件和寫記錄鎖、信號(hào)量
- 共享內(nèi)存:具名、匿名
- 遠(yuǎn)程過程調(diào)用:RPC
網(wǎng)絡(luò)進(jìn)程間通信
本地進(jìn)程可通過進(jìn)程號(hào)(Process ID, PID)唯一標(biāo)識(shí),網(wǎng)絡(luò)中進(jìn)程間如何通信呢?首先要解決的問題是如何唯一標(biāo)識(shí)一個(gè)進(jìn)程,其實(shí)網(wǎng)絡(luò)中TCP/IP已經(jīng)解決了這個(gè)問題。
- 網(wǎng)絡(luò)層 IP地址可以唯一標(biāo)識(shí)網(wǎng)絡(luò)中的主機(jī)
- 傳輸層 “協(xié)議+端口”可以唯一標(biāo)識(shí)主機(jī)中的應(yīng)用程序(進(jìn)程)
“IP地址+協(xié)議+端口”可以標(biāo)識(shí)網(wǎng)絡(luò)的進(jìn)程,網(wǎng)絡(luò)中進(jìn)程通信即可實(shí)現(xiàn)。
什么是Socket
Socket英文愿意是“插孔”或“插座”,作為BSD UNIX的進(jìn)程通信機(jī)制后,取后一種意思,通常也被稱為套接字。使用TCP/IP協(xié)議的應(yīng)用程序通常采用的應(yīng)用編程接是UNIX BSD的套接字Socket,來實(shí)現(xiàn)網(wǎng)絡(luò)進(jìn)程之間的通信。
Socket用于描述IP地址和端口,是一個(gè)通信鏈的句柄,用來實(shí)現(xiàn)不同虛擬機(jī)或物理機(jī)之間的通信。應(yīng)用程序通過Socket向網(wǎng)絡(luò)發(fā)出請求或應(yīng)答請求。網(wǎng)絡(luò)中兩個(gè)進(jìn)程通過一個(gè)雙向的通信連接實(shí)現(xiàn)數(shù)據(jù)的交換,建立網(wǎng)絡(luò)通信連接至少需要一對(duì)Socket,連接的一端稱為一個(gè)Socket。
具有唯一標(biāo)識(shí)的網(wǎng)絡(luò)進(jìn)程可利用 Socket 進(jìn)行通信,而 Socket 是在應(yīng)用層和傳輸層之間的一個(gè)抽象層,Socket把TCP/IP層復(fù)雜的操作抽象為簡單的接口供應(yīng)用層調(diào)用,以實(shí)現(xiàn)進(jìn)程在網(wǎng)絡(luò)中的通信。TCP/IP協(xié)議存在于操作系統(tǒng)中,網(wǎng)絡(luò)服務(wù)是通過操作系統(tǒng)提供的,因此在操作系統(tǒng)中增加支持TCP/IP的系統(tǒng)調(diào)用Socket。
Socket 作為應(yīng)用層與 TCP/IP 協(xié)議簇通信的中間軟件抽象層,是一組接口。在設(shè)計(jì)模式中 Socket 其實(shí)就是一個(gè)門面模式,它將復(fù)雜的 TCP/IP 協(xié)議簇隱藏在 Socket 接口后面。對(duì)用戶而言一組簡單地接口就是全部,讓 Socket 去組織數(shù)據(jù)已符合指定的協(xié)議。

Socket通信流程
Socket可理解為一種特殊的文件,在服務(wù)器和客戶端各自維護(hù)一個(gè)文件,并使用SocketAPI函數(shù)對(duì)其進(jìn)行文件操作。在建立連接打開后,可以向各自文件寫入內(nèi)容供對(duì)方讀取或讀取對(duì)方內(nèi)容,通信結(jié)束時(shí)關(guān)閉文件。在UNIX哲學(xué)中“一切皆文件”,文件的操作模式基本為“打開-讀寫-關(guān)閉”三大步驟,Socket其實(shí)就是這個(gè)模式的一個(gè)實(shí)現(xiàn)。

服務(wù)器
- 服務(wù)器根據(jù)IP地址類型(IPv4/IPv6)、Socket 類型和協(xié)議創(chuàng)建套接字
- 服務(wù)端為 Socket 綁定 IP 地址和端口號(hào)
- 服務(wù)端 Socket 監(jiān)聽端口請求,隨時(shí)準(zhǔn)備接收客戶端發(fā)來的連接,此時(shí) socket 并未被打開。
客戶端
- 客戶端打開 Socket,根據(jù)服務(wù)器 IP 地址和端口試圖連接服務(wù)端的Socket。
- 服務(wù)器Socket接收到客戶端Socket請求,被動(dòng)打開開始接收客戶端請求,直到客戶端返回連接信息,此時(shí) Socket 進(jìn)入阻塞狀態(tài)。
交互過程
- 客戶端連接成功向服務(wù)端發(fā)送連接狀態(tài)信息
- 服務(wù)端 Accept 返回連接成功
- 客戶端向 Socket 寫入數(shù)據(jù)
- 服務(wù)端讀取數(shù)據(jù)
- 客戶端關(guān)閉
伯克利SocketAPI
歷史
- Berkeley sockets 也稱為BSD Socket
- 1983 BSD Socket4.
- 1989 UNIX均采用
- 2008 成為POSIX標(biāo)準(zhǔn)
頭文件
-
sys/socket.h函數(shù)和數(shù)據(jù)結(jié)構(gòu)定義 -
netinet/in.hIPv4和IPv6xiangguan協(xié)議 -
sys/un.hUNIX機(jī)器間通信 -
arpa/inet.h處理數(shù)字從操作系統(tǒng)字節(jié)序到網(wǎng)絡(luò)字節(jié)序 -
netdb.h映射服務(wù)到IP地址
SocketAPI函數(shù)
socket() 創(chuàng)建套接字,根據(jù)指定地址、數(shù)據(jù)類型、協(xié)議分配一個(gè)套接字的描述字及所用資源。
int socket(int domain, int type, int protocol)
參數(shù):
-
domain
協(xié)議簇/域,通常為AF_INET(IPv4)、AF_INET6(IPv6) -
type
套接字類型,主要是SOCK_STREAM(TCP)、SOCK_DGRAM(UDP) -
protocol
通常為0
Socket有3種類型
- 流式
SOCK_STREAM
流失套接字提供可靠的、面向連接的通信流,使用TCP協(xié)議從而保證數(shù)據(jù)傳輸?shù)恼_性和順序性。 - 數(shù)據(jù)報(bào)
SOCK_DGRAM
數(shù)據(jù)包套接字定義了一種無連接的服務(wù),數(shù)據(jù)通過相互獨(dú)立的報(bào)文進(jìn)行傳輸,是無序的,不保證是可靠的無差錯(cuò)的,使用數(shù)據(jù)報(bào)協(xié)議UDP。 - 原始
SOCK_RAW
原始套接字允許對(duì)底層協(xié)議如IP或ICMP進(jìn)行直接訪問,功能強(qiáng)大但使用不便,主要用于協(xié)議開發(fā)。
返回值:
成功時(shí)返回非負(fù)整數(shù)
-
bind()綁定socket到IP地址和端口 -
listen()服務(wù)器監(jiān)聽客戶端的連接 -
connect()客戶端連接到服務(wù)器 -
accept()應(yīng)用程序接收完成3次握手的客戶端連接 send()recv()write()read()-
close()關(guān)閉socket -
gethostbyname()IPv4專用 -
gethostbyaddr()IPv4專用 select()-
poll()處理多個(gè)連接的讀寫和錯(cuò)誤狀態(tài) -
getsocketopt()獲得對(duì)應(yīng)socket的選項(xiàng)值 -
setsocketopt()設(shè)置對(duì)應(yīng)socket的選項(xiàng)值