我正在通過 UDP(uni assignment)實作一個可靠的、面向連接的應用程式。要求服務器在收到來自客戶端的初始資料包并確認后,創建一個新的作業行程。作業行程應該有一個專用于這個特定客戶端的套接字。
現在我看到了三種實作方式。
- 服務器有一個socket,我們叫它
listener_socket,系結到指定埠,等待請求。然后,我可以在子行程中,將connect()這個套接字連接到客戶端地址。 - 或者,我可以
listener_socket完全關閉孩子,然后打開一個全新的套接字connection_socket,將其系結到埠并將其連接到客戶端。 - 或者,在新埠上打開一個新套接字并撰寫客戶端代碼以在連接的剩余時間內處理這個新埠。
我不確定(關于選項1)是連接listener_socket到客戶端如何影響listener_socket父服務器中的原始檔案。它會阻止父級從其他客戶端接收更多訊息嗎?如果不是,為什么?他們最終不是都指的是同一個套接字嗎?
至于選項 2,這讓我非常期待“地址已在使用中”。是否有一些類似于路由器的功能(即最長匹配前綴)將資料報傳遞到“最合適的”套接字?(好吧,TCP 已經這樣做了accept(),所以這個邏輯不太可能被復制到 UDP 中。)
關于選項 3,我認為它的效率很低,因為這意味著我應該為每個客戶端使用一個新埠。
那么有人可以建議使用哪種方法,或者是否有另一種我還不知道的方法?謝謝。
uj5u.com熱心網友回復:
我不確定(關于選項 1)是將 listener_socket 連接到客戶端如何影響父服務器中的原始 listener_socket。它會阻止父級從其他客戶端接收更多訊息嗎?
是的。
如果不是,為什么?他們最終不是都指的是同一個套接字嗎?
是的,當父級分叉子級時,子級會收到所有父級打開檔案描述符的副本,這些副本指的是由內核管理的打開檔案描述。這些打開的檔案描述因此在父母和孩子之間共享。因此,如果孩子connect()是客戶端的套接字,那么父母和孩子都會看到這樣的效果
如果套接字
sockfd型別為SOCK_DGRAM,則 [指定地址] 是默認發送資料報的地址,也是接收資料報的唯一地址。
(Linux 手冊頁;已添加重點)
至于選項 2,這讓我非常期待“地址已在使用中”。是否有一些類似于路由器的功能(即最長匹配前綴)將資料報傳遞到“最合適的”套接字?
是什么讓一個插座比另一個更合適?無論如何,沒有。UDP 端點僅由地址和埠標識。
關于選項 3,我認為它的效率很低,因為這意味著我應該為每個客戶端使用一個新埠。
相對于什么效率低下?是的,您的選項 (3) 需要為每個客戶端指定一個單獨的埠,但您沒有提出任何其他可行的替代方案。
但這并不是說沒有其他可行的替代方案。如果您不想協商一個單獨的埠并為每個客戶端打開一個單獨的套接字(例如,這是 FTP 可以操作的方式之一),那么您不能依賴每個客戶端的 UDP 套接字。在這種情況下,服務的所有傳入流量都必須轉到同一個套接字。但是您可以讓在該套接字上接收訊息的行程根據訊息的源地址和埠將每個訊息分派給適當的合作行程。而且您應該能夠讓這些行程都通過同一個套接字發送回應。
可以通過多種方式設定此類系統的詳細資訊。它們都有一個限制,即接收所有訊息的一個行程可能會成為瓶頸,但實際上,我們談論的是 I/O。主要瓶頸很可能在網路級別,而不是在接收程序中。
uj5u.com熱心網友回復:
如果 fork 后子行程中的套接字與父行程中的套接字相同,則它們都反映了相同的內核套接字。由于系結和連接是在內核套接字上完成的,因此對子套接字的任何更改也會影響父套接字。因此有必要創建一個新的(獨立的)連接套接字。
套接字需要系結到與偵聽器套接字相同的本地地址和埠,因為這是對等方期望資料包來自的地方以保持相同的 UDP 關聯。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/405110.html
標籤:
上一篇:重新啟動套接字時地址已在使用中
