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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1410723/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 22:10:38  来源:igfitidea点击:

Is there a way to reopen a socket?

pythonsockets

提问by dugres

I create many "short-term" sockets in some code that look like that :

我在一些看起来像这样的代码中创建了许多“短期”套接字:

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

This works fine, as long as nbis "small" enough.

这很好用,只要nb足够“小”。

As nbmight be quite large though, I'd like to do something like this

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

So the question is :
Is there any way to "reuse" a socket that has been shutdown ?

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

回答by paxdiablo

No, this is a limitation of the underlying C sockets (and the TCP/IP protocol, for that matter). My question to you is: why are you shutting them down when you can architect your application to use them?

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

The problem with many short-term sockets is that shutting them down puts them in a state where they cannot be used for a while (basically, twice the packet lifetime, to ensure any packets in the network either arrive and are discarded, or get discarded by the network itself). Basically what happens is that, in the 4-tuple that needs to be unique (source ip, source port, destination ip, destination port), the first one and last two tend to always be the same so, when you run out of source ports, you're hosed.

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

We've struck this problem in software before where it only became evident when we ran on faster machines (since we could use many more sessions).

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

Why dont you just open up the socket and continue to use it? It looks like your protocol is a simple request/response one, which should be easily do-able with that approach.

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

Something like:

就像是:

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

Update:

更新:

One possibility (and we've done this before) if you're running out of connection due to this continual open/close, is to detect the problem and throttle it. Consider the following code (the stuff I've added is more pseudo-code than Python since I haven't touched Python for quite a while):

如果由于这种持续打开/关闭而导致连接耗尽,一种可能性(我们之前已经这样做过)是检测问题并对其进行限制。考虑下面的代码(我添加的东西比 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()

Basically, it lets you run at full speed while there are plenty of resources but slows down when you strike your problem area. This is actually what we did to our product to "fix" the problem of failing when resources got low. We would have re-architected it except for the fact it was a legacy product approaching end of life and we were basically in the fix-at-minimal-cost mode for service.

基本上,它可以让您在资源充足的情况下全速运行,但在您遇到问题区域时会减慢速度。这实际上是我们对我们的产品所做的,以“修复”资源不足时失败的问题。我们会重新设计它,除非它是一个接近生命周期的遗留产品,而且我们基本上处于以最低成本修复的服务模式。

回答by JimB

I'm not sure what the extra overhead would be like, but you could fully close and reopen the socket. You need to set SO_REUSEADDR, and bind to a specific port you can reuse.

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

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

回答by codymanix

If you keep opening and closing sockets for the same port then it is better to open this socket once and keep it open, then you will have much better performance, since opening and closing will take some time.

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

If you have many short-term sockets, you may also consider datagram sockets (UDP). Note that you do not have a guarantee for arrival in this case, also order of the packets is not guaranteed.

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

回答by mark4o

You cannot reuse the socket but it would not help if you could, since you are running out of ports, not sockets. Each port will stay in TIME_WAITstatefor twice the maximum segment lifetime after you initiate the shutdown. It would be best not to require so many ports within such a short period, but if you need to use a large number you may be able to increase the ephemeral port range.

您不能重用套接字,但如果可以的话也无济于事,因为您用完了端口,而不是套接字。在您启动关闭后,每个端口将在最大段生命周期的两倍内保持TIME_WAIT状态。最好不要在这么短的时间内需要这么多端口,但是如果您需要使用大量端口,则可以增加临时端口范围

Port numbers are 16 bits and therefore there are only 65536 of them. If you are on Windows or Mac OS X then by default, ephemeral ports are chosen from the range 49152 to 65535. This is the official range designated by IANA, but on Linux and Solaris (often used for high traffic servers) the default range starts at 32768 to allow for more ports. You may want to make a similar change to your system if it is not already set that way and you are in need of more ephemeral ports.

端口号是 16 位,因此只有 65536 个。如果您使用的是 Windows 或 Mac OS X,那么默认情况下,临时端口会从 49152 到 65535 的范围内选择。这是IANA 指定官方范围,但在 Linux 和 Solaris(通常用于高流量服务器)上,默认范围开始在 32768 以允许更多端口。如果您的系统还没有这样设置并且您需要更多的临时端口,您可能希望对系统进行类似的更改。

It is also possible to reduce the maximum segment lifetime on your system, reducing the amount of time that each socket is in TIME_WAITstate, or to use SO_REUSEADDRor SO_LINGERin some cases to reuse ports before the time has expired. However this can at least theoretically cause older connections to be mixed up with newer connections that happen to be using the same port number, if some packets from the older connections are slow to arrive, so is generally not a good idea.

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