2011-06-26 40 views
1

我正在爲本地IPC編寫一個庫,它應該既作爲服務器又作爲客戶端。如果服務器沒有準備好,策略是失敗並重試。如何在服務器未準備好時連接失敗?

對於此測試,我創建了兩個進程作爲服務器和客戶端進行通信。

但是我的當前實現有問題,因爲當服務器忙時客戶端代碼不會失敗。

的問題最好用從strace的片段所示:

execve("./RemoteSubjects", ["./RemoteSubjects"], [/* 72 vars */]) = 0 

// Client A starts 
28069  .000105 socket(PF_FILE, SOCK_STREAM, 0) = 3 
28069  .000031 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) 
28069  .000006 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 
28069  .000047 unlink("/tmp/A.ipc") = 0 
28069  .000007 bind(3, {sa_family=AF_FILE, path="/tmp/A.ipc"}, 110) = 0 
28069  .000007 listen(3, 0) = 0 

// Client B starts 
28070  .000031 socket(PF_FILE, SOCK_STREAM, 0) = 3 
28070  .000012 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) 
28070  .000005 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 
28070  .000030 unlink("/tmp/B.ipc") = 0 
28070  .000034 bind(3, {sa_family=AF_FILE, path="/tmp/B.ipc"}, 110) = 0 
28070  .000027 listen(3, 0)  = 0 

// Client A creates a socket, which it intend to use for communication with B 
28069  .000023 socket(PF_FILE, SOCK_STREAM, 0) = 4 
28069  .000016 fcntl(4, F_GETFL) = 0x2 (flags O_RDWR) 
28069  .000024 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 

// Client B creates a socket, which it intend to use for communication with A 
28070  .000038 socket(PF_FILE, SOCK_STREAM, 0) = 4 
28070  .000016 fcntl(4, F_GETFL <unfinished ...> 

// Client A connects to B 
28069  .000004 connect(4, {sa_family=AF_FILE, path="/tmp/B.ipc"}, 110 <unfinished ...> 

// Client B creates a socket, which it intend to use for communication with A 
28070  .000011 <... fcntl resumed>) = 0x2 (flags O_RDWR) 
28070  .000007 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 

// Client B connects to A 
28070  .000015 connect(4, {sa_family=AF_FILE, path="/tmp/A.ipc"}, 110 <unfinished ...> 

// Client A's connect returned 
28069  .000010 <... connect resumed>) = 0 

// Here is what I do not understand... Why does connect returns 0 when the backlog 
// is set to 0 and B has not accepted? 

我想發生的是,連接失敗了,直到我趕上服務器的事件循環等待投票方式對報告活動文件描述符3.我應該正確設置一個超時(SO_RCVTIMEO/SO_SNDTIMEO我認爲)允許連接阻塞10毫秒來增加服務器接受連接的更改。

但是,我應該如何解決這個問題,並確保連接失敗,如果接受不被稱爲?

回答

2

通過調用listen(),表明您願意允許傳入連接,並創建接受隊列。內核負責在後臺建立連接,在接受隊列上建立新的連接。 accept()函數只是將下一個完全完成的連接從接受隊列中取出,並不會導致發送任何內容。

對於積壓說法,POSIX states that this is a hint

積壓參數提供一個提示,其實施應使用限制套接字的偵聽隊列未完成的連接數的實現。

它還說:

爲0的積壓參數可以允許插座接受連接,在這種情況下,偵聽隊列的長度可以被設置爲一個實現定義的最小值。

如果您希望connect()失敗,請不要致電listen(),直到您準備好讓它成功。在調用accept()之後,如果不想再有更多的連接成功(關閉坐在接受隊列中的任何其他連接將被中止),關閉監聽套接字。或者,讓應用程序在接受連接時通過套接字發送一些數據(如果它尚未這樣做的話);如果對方在特定的超時時間內沒有收到任何內容,則可能會關閉連接。