2009-05-26 149 views
3

Iam嘗試基於數據報套接字(UDP)創建迭代服務器。 它調用連接到它從第一個recvfrom()調用獲得的第一個客戶端(是的,我知道這不是真正的連接)。 服務此客戶端後,我斷開UDP套接字(調用連接AF_UNSPEC) 然後我調用recvfrom()從下一個客戶端獲取第一個數據包。斷開並重新連接已連接的數據報套接字

現在的問題是,在循環的第二個迭代recvfrom()的調用返回0.我的客戶端永遠不會發送空數據包,所以會發生什麼。

這是什麼做的IAM(僞):

s = socket(PF_INET, SOCK_DGRAM, 0) 

bind(s) 

for(;;) 
{ 
    recvfrom(s, header, &client_address) // get first packet from client 
    connect(s,client_address) // connect to this client 
    serve_client(s); 
    connect(s, AF_UNSPEC); // disconnect, ready to serve next client 
} 

編輯:我找到的bug在我的客戶不小心發送一個空包。 現在我的問題是如何讓客戶端等待得到服務,而不是發送請求到任何地方(服務器連接到另一個客戶端,並且不提供任何其他客戶端)。

回答

3

SOCK_DGRAM上的connect()實際上完全沒有必要。

調用連接不會阻止您接收來自其他主機的數據包,也不會阻止您發送它們。只是不要打擾,這不是真的有幫助。

更正:是的,顯然它確實會阻止您接收來自其他主機的數據包。但是在服務器上這樣做有點愚蠢,因爲在連接()到一個時,其他客戶端將被鎖定。此外,你仍然需要捕捉浮動的「糠」。在DGRAM套接字上可能存在一些與connect()相關的競爭條件 - 如果調用connect並且來自其他主機的數據包已經在緩衝區中,會發生什麼情況?

另外,0是來自recvfrom()的有效返回值,因爲空(無數據)數據包是有效的並且可以存在(事實上,人們經常使用它們)。所以你不能檢查是否有某種成功的方式。

在所有可能的情況下,零字節數據包已經在隊列中。

您的協議應該設計爲最大限度地減少錯誤數據報被誤解的機會;因爲這個原因,我建議你不要使用空數據報,而是使用一個幻數。

UDP應用程序必須能夠識別「chaff」數據包並丟棄它們;他們遲早會出現。

+0

Connect使用send()或recv()函數設置一個內部過濾器,從中接收和發送地址。 recv():「對於SOCK_DGRAM套接字,從連接調用中指定的目標地址的第一個排隊數據報中提取數據」。 – codymanix 2009-05-26 16:30:07

+0

你是對的,我的客戶正在發送(由於錯誤)一個空包。現在我有另一個問題。應該在隊列中等待獲得服務的客戶端發送其第一個請求數據包(從未從服務器接收數據包)。然後它嘗試接收響應,並且recv返回-1。我如何讓客戶等待? – codymanix 2009-05-26 21:15:03

0

man connect

 
... 
If the initiating socket is not connection-mode, then connect() 
shall set the socket’s peer address, and no connection is made. 
For SOCK_DGRAM sockets, the peer address identifies where all 
datagrams are sent on subsequent send() functions, and limits 
the remote sender for subsequent recv() functions. If address 
is a null address for the protocol, the socket’s peer address 
shall be reset. 
... 
-1

只是一個在校的情況下任何人碰到這個stumbples像我一樣。斷開connect()需要使用設置爲AF_UNSPEC的sockaddr的sa_family成員來調用。不只是通過AF_UNSPEC。

相關問題