服务器未就绪时如何使连接失败?

时间:2011-06-26 14:54:56

标签: c linux sockets network-programming operating-system

我正在为本地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,我认为)允许连接阻止10ms以增加服务器接受连接的更改。

但是我应该如何解决这个问题,如果没有调用accept,请确保连接失败?

1 个答案:

答案 0 :(得分:2)

通过调用listen(),表明您愿意允许传入连接,并创建接受队列。内核负责在幕后建立连接,在接受队列上建立新连接。 accept()函数只接受接受队列中的下一个完全完成的连接,并且不会导致发送任何内容。

至于积压参数,POSIX states that this is a hint

  

backlog参数提供了一个实现的提示,实现将使用它来限制套接字侦听队列中未完成连接的数量。

它还说:

  

backlog参数为0可能允许套接字接受连接,在这种情况下,侦听队列的长度可以设置为实现定义的最小值。

如果您希望connect()失败,请在您准备好成功之前不要致电listen()。在调用accept()之后,如果您不希望任何其他连接成功,请关闭侦听套接字(将中止接受队列中的任何其他连接)。或者,让应用程序在接受连接后通过套接字发送一些数据(如果它还没有这样做);如果对方在某个超时时间内没有收到任何内容,则可以关闭连接。