非阻塞accept
当一个已完成的连接准备好被accept的时候,select会把监听socket标记为可读。因此,如果用select等待外来的连接时,应该不需要把监听socket设置为非阻塞模式,因为如果select告诉我们连接已经就绪,accept就不应该被阻塞。不过这样做的时候有一个BUG:当客户端在跟服务器建立连接之后发送了一个RST包,这个时候accept就会阻塞,直到有下一个已完成的连接准备好被accept为止。
struct linger的l_onoff标志设为1,l_linger设为0。这个时候,如果关闭TCP连接时,会先在socket上发送一个RST包。这个时候会出现下面的问题:
A:select向服务器返回监听socket可读,但是服务器要在一段时间之后才能调用accept;
B:在服务器从select返回和调用accept之前,收到从客户发送过来的RST;
C:这个已经完成的连接被从队列中删除,我们假设没有其它已完成的连接存在;
D:服务器调用accept,但是由于没有其它已完成的连接存在,因而服务器被阻塞了;
注意,服务器会被一直阻塞在accept调用上,直到另外一个客户建立一个连接为止;但是如果一直没有其它客户建立连接,那么服务器将仍然一直被阻塞在accept调用上,不处理任何其他已就绪的socket;
解决这个问题的办法是:
A:如果使用select来获知何时有链接已就绪可以accept时,总是把监听socket设置为非阻塞模式,并且
B:在后面的accept调用中忽略以下错误:EWOULDBLOCK(源自Berkeley的实现在客户放弃连接时出现的错误)、ECONNABORTED(Posix.1g的实现在客户放弃连接时出现的错误)、EPROTO(SVR4的实现在客户放弃连接时出现的错误)和EINTR(如果信号被捕获).
非阻塞connect
在一个TCP套接口被设置为非阻塞之后调用co