用select来判断监听套接字是否有请求时引起阻塞

这两天发现一个问题,有一个服务用来select来判断监听套接字时,有时候会阻塞在accept那里,到有再次连接过去时才正常循环。这很奇怪,select已经标明了监听套接字有读事件了,这代表有请求进来啊,accept时怎么还会被阻塞呢?
今晚在看《unix网络编程》时,突然看到SO_LINGER这个选项,当将linger.l_onoff设置为1而linger.l_linger设置为零时,close掉该socket时是会立刻发送一个RST进入CLOSED状态,而没有通常的四分组连接终止序列。
模拟了一下这种情况,但是还是时会时不会。后来仔细想了一下,真相应该是这样的:
当服务器在select返回监听套接字的可读条件后,可能无法马上就调用accept,这时候客户端再在服务端调用accept前发出RST分节,就会导致已完成的连接被服务器TCP驱除出队列,这时候再accept,如果请求队列里没有其他连接了,就会导致accept被阻塞到下次连接请求到来了。
再在select返回后sleep 1秒,果然现在每次都会被阻塞住。
后来再翻了下非阻塞accept章节那里,也提到了这个问题。并提出了下面的解决方案:
1、当使用select获悉某个监听套接字上何时有已完成连接准备好被accept时,总是把这个监听套接字设置为非阻塞。
2、在后续的accept调用中忽略以下的错误:EWOULDBLOCK(源自Berkeley的实现,客户中止连接时)、ECONNABORTED(POSIX实现,客户中止连接时)、EPROTO(SVR4实现,客户中止连接时)和EINTR(如果有信号被捕获)。

标签: , ,
文章分类 Unix/Linux
3 comments on “用select来判断监听套接字是否有请求时引起阻塞
  1. zhazha说道:

    在服务器的开发里面本来任何操作就都不应该采用阻塞的模型,除非阻塞的部分在另一个线程。recv也是有可能卡死的。

    [回复]

    colaghost 回复:

    目前这边的一种场景就是多线程加同步的,数据的收发在别的线程里完成,同步读,但是会设置超时。不过这个用得少了,一些老的模块原来是那样就没去改了,现在都是用libevent这种异步单线程的,只是写起代码来就痛苦一点

    [回复]

  2. Kendra Fondren说道:

    This is awesome!

    [回复]

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*