有办法重新打开插座吗?

2024-04-29 07:27:27 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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()

所以问题是:
有什么方法可以“重用”已经关闭的套接字吗?


Tags: answerinsendforstreamconnectrangesocket
3条回答

如果您继续为同一端口打开和关闭套接字,那么最好将此套接字打开一次并保持打开状态,这样您的性能会更好,因为打开和关闭将需要一些时间。

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

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

许多短期套接字的问题是,关闭它们会使它们处于暂时无法使用的状态(基本上是数据包生存期的两倍,以确保网络中的任何数据包要么到达并被丢弃,要么被网络本身丢弃)。基本上,在需要唯一的4元组(源ip、源端口、目标ip、目标端口)中,前一个和后两个往往总是相同的,因此,当您用完源端口时,您就被hose占用了。

我们以前在软件中遇到过这个问题,当我们运行在更快的机器上时(因为我们可以使用更多的会话),这个问题才变得明显。

为什么不打开插座继续使用呢?看起来您的协议是一个简单的请求/响应协议,使用这种方法应该很容易实现。

类似于:

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()

基本上,它可以让你全速运行,同时有足够的资源,但当你打击你的问题领域时会减慢速度。这实际上是我们对我们的产品所做的“修复”当资源不足时失败的问题。我们本可以重新设计它,除非它是一个接近生命尽头的遗留产品,而且我们基本上是在以最低成本模式修复服务。

我不知道额外的开销会是什么样子,但你可以完全关闭并重新打开插座。您需要设置以便重用ADR,并绑定到可以重用的特定端口。

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

相关问题 更多 >