2013-12-09 166 views
5

此问题不限于Python。它是一个普通的socket问题。我有一个非阻塞套接字,并希望连接到可以访问的计算机 - 另一方面,该端口不存在。为什么select(...)无论如何都会成功?我期待暂停。 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() 

回答

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()正如我在上面所做的那样,在尝试对其执行任何操作之前,检查套接字是否正确或处于错误状态。
+0

sock.getsockopt(socket.SOL_SOCKET,socket.SO_ERROR)为我做了诡计。 – HelloWorld

+1

好的。请记住,套接字可以在'getsockopt()'返回以及您尝试读取或写入套接字之间关闭。所以你仍然应该尝试正确地处理send/recv错误。 – mpontillo