有没有办法重新打开套接字?

时间:2009-09-11 13:00:14

标签: python sockets

我在一些代码中创建了许多“短期”套接字:

nb=1000
for i in range(nb):
    sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sck.connect((adr, prt)
    sck.send('question %i'%i)
    sck.shutdown(SHUT_WR)
    answer=sck.recv(4096)
    print 'answer %i : %s' % (%i, answer)
    sck.close()

只要 nb 足够“小”,这样就可以了。

因为 nb 可能会非常大,我想做这样的事情

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.connect((adr, prt)
for i in range(nb):
    reopen(sck) # ? ? ?
    sck.send('question %i'%i)
    sck.shutdown(SHUT_WR)
    answer=sck.recv(4096)
    print 'answer %i : %s' % (%i, answer)
sck.close()

所以问题是:
有没有办法“重用”已经关闭的套接字?

4 个答案:

答案 0 :(得分:17)

不,这是底层C套接字(以及TCP / IP协议)的限制。我向您提出的问题是:当您构建应用程序以使用它们时,为什么要关闭它们?

许多短期套接字的问题在于关闭它们会使它们暂时无法使用(基本上是数据包生命周期的两倍,以确保网络中的任何数据包到达并被丢弃,或被网络本身丢弃)。基本上会发生的事情是,在需要唯一的4元组(源IP,源端口,目标IP,目标端口)中,第一个和后两个往往总是相同的,所以当你耗尽源代码时港口,你被冲洗了。

我们已经在软件中解决了这个问题,之后只有当我们在更快的机器上运行时才变得明显(因为我们可以使用更多的会话)。

为什么不打开插座并继续使用它?看起来您的协议是一个简单的请求/响应协议,应该可以轻松地使用该方法。

类似的东西:

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.connect((adr, prt)
for i in range(nb):
    sck.send('question %i'%i)
    answer=sck.recv(4096)
    print 'answer %i : %s' % (%i, answer)
sck.close()

更新

如果由于持续打开/关闭导致连接不足,一种可能性(之前我们已经这样做过)就是检测问题并加以限制。考虑下面的代码(我添加的东西比Python更多的伪代码,因为我已经很长时间没有触及Python了):

for i in range(nb):
    sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sck.connect((adr, prt)

    while sck.error() == NO_SOCKETS_AVAIL:
        sleep 250 milliseconds
        sck.connect((adr, prt)

    sck.send('question %i'%i)
    sck.shutdown(SHUT_WR)
    answer=sck.recv(4096)
    print 'answer %i : %s' % (%i, answer)
    sck.close()

基本上,它可让您在资源充足的情况下全速运行但在遇到问题区域时速度会变慢。这实际上是我们对我们的产品所做的,以“解决”资源不足时失败的问题。我们会重新构建它,除了它是一个接近使用寿命的遗留产品,我们基本上处于固定最低成本的服务模式。

答案 1 :(得分:3)

我不确定额外的开销是多少,但你可以完全关闭并重新打开套接字。您需要设置SO_REUSEADDR,并绑定到您可以重用的特定端口。

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

答案 2 :(得分:1)

如果你继续打开和关闭相同端口的套​​接字,那么最好打开一次这个套接字并保持打开状态,然后你会有更好的性能,因为打开和关闭需要一些时间。

如果您有许多短期套接字,您还可以考虑使用数据报套接字(UDP)。 请注意,在这种情况下,您无法保证到达,也无法保证数据包的顺序。

答案 3 :(得分:0)

你不能重复使用套接字,但是如果可以的话就没有用,因为你的端口用完了,而不是套接字。启动关闭后,每个端口将保持TIME_WAIT state两倍的最大段生命周期。最好不要在如此短的时间内需要这么多端口,但如果你需要使用大量端口,你可以增加ephemeral port range

端口号为16位,因此只有65536个。如果您使用的是Windows或Mac OS X,则默认情况下,临时端口的选择范围为49152到65535.这是official range designated by IANA,但在Linux和Solaris(通常用于高流量服务器)上,默认范围开始在32768允许更多的端口。您可能希望对系统进行类似的更改,如果它尚未设置,并且您需要更多短暂的端口。

还可以减少系统上的最大段寿命,减少每个套接字处于TIME_WAIT状态的时间,或者在某些情况下使用SO_REUSEADDRSO_LINGER在时间到期之前重用端口的情况。然而,这至少可以理论上导致较旧的连接与恰好使用相同端口号的较新连接混淆,如果来自较旧连接的一些数据包很慢到达,所以通常不是一个好主意。