非阻塞连接

时间:2013-12-09 17:15:14

标签: python sockets networking nonblocking

这个问题不仅限于Python。这是一个普通的插座问题。我有一个非阻塞套接字,并希望连接到可访问的机器 - 另一方面端口不存在。为什么选择(...)成功呢?我预计会超时。 sock.send(...)因管道损坏而失败。如何在选择(...)后确定套接字是否真正连接? 提前谢谢。

import socket, errno, os, time, select

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(0)
err = sock.connect_ex(('192.168.178.21', 12345))
ready_to_read, ready_to_write, in_error = select.select([], [sock], [], timeout=5)
#ready_to_write is set even 192.168.178.21:12345 does not exist.

sock.setblocking(1)
sock.send('foo') #this fails
sock.close()

1 个答案:

答案 0 :(得分:4)

尝试检查返回值。以下是我在类似情况下得到的结果:

>>> import socket, errno, os, time, select
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sock.setblocking(0)
>>> err = sock.connect_ex(('10.0.0.1', 12345))
>>> import errno
>>> print errno.errorcode[err]
EINPROGRESS
>>> print sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
61
>>> print errno.errorcode[61]
ECONNREFUSED

select()调用可能正在返回,因为套接字上存在异常情况 - 也就是说,它的连接被拒绝了。

如果我这样做,select()会立即返回:

>>> ready_to_read, ready_to_write, in_error = select.select([], [sock], [])

有趣的是,返回值与您传入的内容完全匹配(如果您有多个套接字,那可能会有所不同):

>>> print in_error
[]
>>> print ready_to_read
[]
>>> print ready_to_write
[<socket._socketobject object at 0x10ccd0980>]

select()的设计者期望您在循环中运行select(),如果套接字在您尝试写入时返回错误,则在写入失败时将其从列表中删除。

所以你有几个选择,我的头脑:

  • 等到您尝试读取套接字并失败,然后采取适当的措施。
  • 在尝试对其执行任何操作之前,按照上面的操作使用getsockopt()检查套接字是否正常,或处于错误状态。