如何获得非阻塞套接字connect()?

时间:2009-07-30 10:58:16

标签: python sockets asynchronous nonblocking

我这里有一个非常简单的问题。我需要同时与很多主机进行通信,但我并不需要任何同步,因为每个请求都非常自给自足。

因此,我选择使用异步套接字,而不是发送垃圾邮件。 现在我确实遇到了一些问题:

async的东西就像魅力一样,但当我连接到100个主机,并且我得到100次超时(超时= 10秒)然后我等待1000秒,只是为了找出我的所有连接都失败了。

有没有办法让非阻塞套接字连接? 我的套接字已设置为nonBlocking,但对connect()的调用仍然阻塞。

减少超时是不可接受的解决方案。

我在Python中这样做,但我想在这种情况下编程语言并不重要。

我真的需要使用线程吗?

5 个答案:

答案 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模块?可能就是你需要的。