Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 有办法重新打开插座吗?_Python_Sockets - Fatal编程技术网

Python 有办法重新打开插座吗?

Python 有办法重新打开插座吗?,python,sockets,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'

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

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()
所以问题是:

有没有办法“重用”已关闭的套接字?

没有,这是底层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):


基本上,它可以让你在有大量资源的情况下全速奔跑,但当你遇到问题时,速度会减慢。这实际上就是我们对产品所做的,以“修复”资源不足时出现故障的问题。我们本来会对它进行重新设计,但事实上它是一个即将使用寿命结束的遗留产品,我们基本上处于以最低成本进行修复的服务模式。

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

如果您有许多短期套接字,您也可以考虑数据报套接字(UDP)。


请注意,在这种情况下,您不能保证到达,也不能保证数据包的顺序。

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

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

您不能重用套接字,但如果可以,则不会有帮助,因为您的端口(而不是套接字)已用完。启动关机后,每个端口将停留在两倍于最大段生存期的时间内。最好不要在如此短的时间内需要如此多的端口,但如果需要使用大量端口,则可以增加端口数量

端口号为16位,因此只有65536位。如果您使用的是Windows或Mac OS X,则默认情况下,临时端口的选择范围为49152到65535。这是最新版本,但在Linux和Solaris(通常用于高流量服务器)上,默认范围从32768开始,以允许更多端口。如果系统尚未设置为这种方式,并且需要更多临时端口,则可能需要对系统进行类似的更改


还可以减少系统上的最大段生存期,减少每个套接字处于
time\u WAIT
状态的时间,或者在某些情况下使用
SO\u REUSEADDR
SO\u LINGER
在时间到期之前重用端口。但是,这至少在理论上会导致旧连接与使用相同端口号的新连接混淆,如果来自旧连接的某些数据包到达速度较慢,则通常不是一个好主意。

我希望我可以这样做,但不幸的是,我必须关闭套接字(或至少“半关闭”)它)否则发送呼叫阻塞,我永远无法得到答案。我猜如果我不关闭套接字,服务器就不知道我已经发送完数据并等待更多的数据。您必须重写服务器,然后让它使用基于数据流中分隔符的更“合理”的方法(例如)。但还有另一种可能性——请参阅我的更新,了解我们解决问题的方法。@pax:我已经实现了您的解决方案,它对任何“nb”都非常有效。非常感谢。没问题,@dugres,它对我们的传统产品也能很好地工作,尽管它大约在2年前就结束了。有些客户就是无法忘记过去:-)这真是一个可怕的黑客行为。最好保持套接字打开并继续使用它。只有当协议设计为支持该协议,并且所有连接都指向同一个位置时,才能继续使用它。当然,如果你能做到这一点就更好了,但是OP说服务器需要在响应之前关闭连接。这正是我所需要的。我忘了创建一个新的套接字实例以重新打开。注意创建一个新的套接字实例,否则会出现“坏文件描述符”错误。
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)