我这里有一个非常简单的问题.我需要同时与很多主机通信,但我并不需要任何同步,因为每个请求都非常自给自足.
因此,我选择使用异步套接字,而不是发送垃圾邮件.现在我有一点问题:
异步的东西就像魅力一样,但当我连接到100个主机,并且我得到100次超时(超时= 10秒)然后我等待1000秒,只是为了找出我的所有连接都失败了.
有没有办法得到非阻塞套接字连接?我的套接字已设置为nonBlocking,但对connect()的调用仍然是阻塞的.
减少超时是不可接受的解决方案.
我在Python中这样做,但我想在这种情况下编程语言并不重要.
我真的需要使用线程吗?
使用该select
模块.这允许您等待多个非阻塞套接字上的I/O完成.这里有一些关于选择的更多信息.从链接到页面:
在C中,编码
select
相当复杂.在Python中,它是一块蛋糕,但它与C版本足够接近,如果您理解Python中的select,那么在C语言中你会遇到一些麻烦.
ready_to_read, ready_to_write, in_error = select.select( potential_readers, potential_writers, potential_errs, timeout)
你传递了
select
三个列表:第一个包含你可能想要尝试阅读的所有套接字; 您可能想要尝试写入的第二个所有套接字,以及要检查错误的最后一个(通常为空).您应该注意,套接字可以进入多个列表.该select
呼叫是阻止的,但您可以暂停.这通常是一件明智的事情 - 给它一个很长的超时(比如一分钟),除非你有充分的理由不这样做.作为回报,您将获得三个列表.它们具有实际可读,可写和错误的套接字.这些列表中的每一个都是您传入的相应列表的子集(可能为空).如果您将套接字放在多个输入列表中,它将只(最多)在一个输出列表中.
如果一个套接字位于输出可读列表中,那么你就可以接近确定这个
recv
套接字将返回的东西.可写清单的想法相同.你能send
做点什么.也许不是你想要的全部,但有些东西总比没有好.(实际上,任何合理健康的套接字都将返回为可写 - 它只是意味着出站网络缓冲区空间可用.)如果您有"服务器"套接字,请将其放在potential_readers列表中.如果它出现在可读列表中,那么您的接受(几乎肯定)会起作用.如果您已创建新套接字以连接到其他人,请将其放在potential_writers列表中.如果它出现在可写列表中,那么它有很大的可能性已连接.
不幸的是,没有示例代码显示错误,所以有点难以看出这个块来自何处.
他做了类似的事情:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setblocking(0) s.connect(("www.nonexistingname.org", 80))
套接字模块在内部使用getaddrinfo,这是一个阻塞操作,尤其是当主机名不存在时.符合标准的dns客户端将等待一段时间,看看该名称是否确实存在,或者是否只涉及一些慢速DNS服务器.
解决方案是仅连接到ip-addresses或使用允许非阻塞请求的dns客户端,如pydns.
您还需要并行化连接,因为设置超时时套接字会阻塞.或者,您无法设置超时,并使用选择模块.
您可以使用asyncore模块中的调度程序类执行此操作.看一下基本的http客户端示例.该类的多个实例不会在连接上相互阻塞.您可以使用线程轻松完成此操作,我认为使跟踪套接字超时更容易,但由于您已经在使用异步方法,因此您也可以保持在同一轨道上.
例如,以下内容适用于我的所有Linux系统
import asyncore, socket class client(asyncore.dispatcher): def __init__(self, host): self.host = host asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect((host, 22)) def handle_connect(self): print 'Connected to', self.host def handle_close(self): self.close() def handle_write(self): self.send('') def handle_read(self): print ' ', self.recv(1024) clients = [] for i in range(50, 100): clients.append(client('cluster%d' % i)) asyncore.loop()
在cluster50 - cluster100中,有许多机器没有响应或不存在.这会立即开始打印:
Connected to cluster50 SSH-2.0-OpenSSH_4.3 Connected to cluster51 SSH-2.0-OpenSSH_4.3 Connected to cluster52 SSH-2.0-OpenSSH_4.3 Connected to cluster60 SSH-2.0-OpenSSH_4.3 Connected to cluster61 SSH-2.0-OpenSSH_4.3 ...
然而,这并未考虑必须阻止的getaddrinfo.如果您在解决dns查询时遇到问题,那么一切都必须等待.您可能需要单独收集dns查询,并在异步循环中使用ip地址
如果你想要一个比asyncore更大的工具包,请看看Twisted Matrix.进入它有点沉重,但它是python可以获得的最好的网络编程工具包.