可以的!
先看一般的socket建立連接的雙方的過程:
客戶端:
socket()
---->創建出 active_socket_fd
(client_socket_fd
)
bind()
--->把active_socket_fd
與ip,port
綁定起來
connect()
--->client_socket_fd
主動請求服務端的 listen_socket_fd
read()/write()
---->讀/寫 socket io
close()
---->關閉socket_fd
服務端:
socket()
---->創建出 active_socket_fd
bind()
--->把active_socket_fd與ip,port綁定起來
listen()
---->active_socket_fd--> listen_socket_fd 等待客戶端的client_socket_fd來請求連接
accept()
---->listen_socket_fd-->connec_socket_fd 把監聽socket轉變為連接socket,用於建立連接后的讀寫數據
read()/write()
---->讀/寫 socket io
close()
---->關閉socket_fd
linux內核中,socket函數不管在客戶端還是服務端,創建的套接字都是主動socket,但是在服務端經過listen(),后把其轉變為listen_socket_fd(被動監聽socket),經過accept()后轉變為connect_socket_fd(已連接socket)。
在轉變為connect_socket_fd之前,都是同一個socket,只不過socket的狀態改變了,但是服務端經過accept()后返回的socket是新的socket,用於連接后的read()/write()。
一個tcp連接的唯一標識是一個四元組<clientIP, clientPort, serverIP, serverPort>,serverIP和serverPort是固定的,假定客戶端也只有一個,即clientIP也是固定的,則描述不同的tcp連接就只剩下clientPort了。而實際上每當客戶端調用connect()函數試圖與服務端建立連接時,內核會為客戶端分配一個臨時端口作為源端口clientPort,服務端通過accept()函數感知到這個連接時,將返回一個全新的tcp連接的描述字(connect_socket_fd)。
所以,一個服務端端口是能建立多個連接的,因為每個連接中clientPort都是不同的,在進行通信時,操作系統接收到向serverPort發來的數據時,會在該端口產生的連接中查找到符合這個唯一標識並傳遞信息到對應的緩沖區。
Ps:順便擴展一下:
1)為什么服務端需要產生兩個socket(listen_socket_fd和connect_socket_fd)
答:監聽socket是服務器作為客戶端連接請求的一個對端,只需創建一次即可,它存在於服務器的整個生命周期,可為成千上萬的客戶端服務,而一旦一個客戶端和服務器連接成功,完成了TCP三次握手,操作系統內核就為這個客戶端生成一個已連接套接字(connect_socket_fd),讓應用服務器使用這個connect_socket_fd和客戶端進行通信,如果應用服務器完成了對這個客戶端的服務,那么關閉的就是已連接套接字,這樣就完成了TCP連接的釋放。請注意,這個時候釋放的只是這一個客戶端連接,其它被服務的客戶端連接可能還存在。最重要的是,監聽套接字一直都處於“監聽”狀態,等待新的客戶請求到達並服務。若只使用一個listen_socket_fd完成從創建監聽到被請求連接,處理請求,關閉socket的整個過程,那么這個socket就會一直被占用,而不能被其它的客戶端請求,造成服務端性能低下。使用兩個socket,按職責分工,listen_socket_fd專門負責響應客戶端的請求,每個新的connect_socket_fd專門負責該次連接的數據交互,分層協作,提高服務端的性能。
2)一個端口能建立多個UDP連接么?
答:UDP本身是無連接的,所以不存在什么多個UDP連接。只是服務端接收UDP數據需要bind一個端口,一個socket只能綁定到一個端口。
參考: