我这里有一个非常简单的问题。我需要同时与很多主机进行通信,但我并不需要任何同步,因为每个请求都非常自给自足。
因此,我选择使用异步套接字,而不是发送垃圾邮件。 现在我确实遇到了一些问题:
async的东西就像魅力一样,但当我连接到100个主机,并且我得到100次超时(超时= 10秒)然后我等待1000秒,只是为了找出我的所有连接都失败了。
有没有办法让非阻塞套接字连接? 我的套接字已设置为nonBlocking,但对connect()的调用仍然阻塞。
减少超时是不可接受的解决方案。
我在Python中这样做,但我想在这种情况下编程语言并不重要。
我真的需要使用线程吗?
答案 0 :(得分:8)
使用select
模块。这允许您等待多个非阻塞套接字上的I / O完成。选择此处为some more information。从链接到页面:
在C中,编码
select
相当复杂。 在Python中,它是一块蛋糕,但是 它足够接近C版本 如果你理解选择 Python,你会遇到一些麻烦 在C中用它。
ready_to_read, ready_to_write, in_error = select.select(
potential_readers,
potential_writers,
potential_errs,
timeout)
你传递
select
三个列表:第一个 包含您可能的所有套接字 想尝试阅读;第二个全部 您可能想要尝试的套接字 写作,和最后(通常 留空了)那些你想要的 检查错误。你应该注意到这一点 套接字可以进入多个套接字 名单。select
来电正在阻止,但是 你可以给它一个超时。这是 通常是一件明智的事情 - 给它一个很好的长时间超时(比如说 分钟)除非你有充分的理由 不这样做。作为回报,您将获得三个列表。 他们有插座 实际上是可读的,可写的和 错误。这些列表中的每一个都是子集 相应的(可能是空的) 你输入的名单。如果你放了一个 它在多个输入列表中的套接字 只会(最多)在一个输出中 列表。
如果输出中的套接字可读 列表,你可以 如关闭到某些-AS-WE-不断得到功能于这个企业 该套接字上的
recv
将返回 一些东西。可写的相同想法 名单。你将能够send
一些东西。也许不是你想要的全部, 但事情总比没有好。 (实际上,任何相当健康的 socket将以可写为单位返回 - 它 只是指出站网络缓冲区 空间可用。)如果您有“服务器”套接字,请将其放入 在potential_readers列表中。如果它 出现在可读的列表中,你的 接受(几乎可以肯定)工作。 如果你已经创建了一个新的套接字 连接到别人,把它放在 potential_writers列表。如果它出现了 在可写清单中,你有一个 它已经连接的好机会。
答案 1 :(得分:7)
不幸的是,没有显示错误的示例代码,因此很难看出这个块来自何处。
他做了类似的事情:
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。
答案 2 :(得分:5)
您还需要并行化连接,因为设置超时时套接字会阻塞。或者,您无法设置超时,并使用选择模块。
您可以使用asyncore模块中的调度程序类执行此操作。看一下基本http client example。该类的多个实例不会在连接上相互阻塞。您可以使用线程轻松完成此操作,我认为使跟踪套接字超时更容易,但由于您已经在使用异步方法,因此您也可以保持在同一轨道上。
例如,以下内容适用于我的所有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可以获得的最佳网络编程工具包。
答案 3 :(得分:4)
使用twisted。
它是一个用Python编写的异步网络引擎,支持多种协议,您可以添加自己的协议。它可用于开发客户端和服务器。它不会阻止连接。
答案 4 :(得分:0)
您是否看过asyncore模块?可能就是你需要的。