Python:如何干净地关闭套接字以避免';无法分配请求的地址';错误(高频)
我在localhost上有一个用c运行的服务器。 我不确定在这里显示相关代码是否有意义(它是从中得到强烈启发的) 在同一台机器上,我有一个python客户端,其代码如下:Python:如何干净地关闭套接字以避免';无法分配请求的地址';错误(高频),python,c,sockets,server,frequency,Python,C,Sockets,Server,Frequency,我在localhost上有一个用c运行的服务器。 我不确定在这里显示相关代码是否有意义(它是从中得到强烈启发的) 在同一台机器上,我有一个python客户端,其代码如下: import socket,sys,struct,time,threading,random from frequency_counter import Frequency_counter # careful ! must be same as c counter parts
import socket,sys,struct,time,threading,random
from frequency_counter import Frequency_counter
# careful ! must be same as c counter parts
SL_PORT = 862
BUFFER_SIZE = 4096
REQUEST_CODE = -1
INT_SIZE = struct.calcsize('i')
FLOAT_SIZE = struct.calcsize('f')
class _open_socket(object):
def __init__(self):
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#self._socket.bind(('localhost',0))
self._socket.connect(('localhost',SL_PORT))
def __enter__(self): return self._socket
def __exit__(self,type,value,trace): self._socket.close()
def send_floats(*floats):
with _open_socket() as socket_:
packed_data = struct.pack('i'+'f'*len(floats),len(floats),*floats)
packed_data = packed_data+'0'*(BUFFER_SIZE-len(packed_data))
socket_.sendall(packed_data)
def receive_floats():
with _open_socket() as socket_:
packed_data = struct.pack('i',REQUEST_CODE,)
packed_data = packed_data+'0'*(BUFFER_SIZE-len(packed_data))
socket_.sendall(packed_data)
data = socket_.recv(BUFFER_SIZE)
nb_received = struct.unpack('i',data[:INT_SIZE])[0]
received = struct.unpack('f'*nb_received,data[INT_SIZE:INT_SIZE+nb_received*FLOAT_SIZE])
return received
if __name__ == "__main__":
freq_counter = Frequency_counter()
while(True):
floats = [random.random() for _ in range(50)]
send_floats(*floats)
received = receive_floats()
freq_counter.tick()
print "frequency : ",freq_counter.get()
#time.sleep(0.001)
此代码以非常高的频率(约5000Hz)运行几秒钟,然后频率在几秒钟内降低到500Hz左右,最后行“self.\u socket.connect…”抛出错误“无法分配请求的地址”
通过添加对time.sleep的调用来降低频率并没有解决问题(只是,在抛出异常之前,事情会运行更长的时间)
在调查发生的事情时,我发现:
显然,“短暂”范围内的所有端口都被使用(?)。显然,关闭打开的插座没有帮助(?)
按照上面文档的建议,我开始使用SO_REUSEADDR选项(open_socket类中的注释代码)。
没有抛出错误,但频率开始变化,周期为4000Hz,周期为40Hz(最新的周期不符合我的需要)
这种方法不适合非常高的频率交换,还是我可以做些什么
编辑:在关闭套接字之前,尝试在服务器端和客户端调用“shutdown”函数。没有更改任何内容。由于对问题的评论,找到了解决方案:
- 首先,c部分是相关的。当数据被发送到它时,它没有发送任何东西回来。我当时没有拿到,那是强制性的。我猜结果是相关的套接字没有关闭,因此很难为新的套接字找到新的端口。让c方始终回答这个问题就解决了
- 禁用nagle允许从3000Hz到4000Hz。它是这样做的
int nodelay_flag = 1;
setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (void*) &nodelay_flag, sizeof(int));
python方面:
socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- 重复使用同一个套接字(而不是为每次数据传输创建一个新的套接字)将频率提高到11000Hz。它需要(有限)修改C和Python端。我想这样做的副作用是,只有一个客户机可以连接到服务器,但这符合我的需要
lsof-p PID | wc
的操作,让您大致了解这一点。大多数linux系统中的临时端口范围在配置文件/proc/sys/net/ipv4/ip_local_port_range
中定义。您可以对该文件进行分类,并检查您可以使用的端口总数,如果您有根用户,您还可以通过对文件的简单回显来增加ephmeral端口的数量prvilages@cmidi它创建了56478 socketsTry,将添加到套接字类中?是的,但在任何情况下,对于给定的ip地址,套接字结构只能容纳2个字节,即16位,即最多65535个端口号,它将耗尽无论如何,除非您使用SO\u REUSEADDR
socket选项。在任何情况下,您都可以将其增加echo“1000 65001”>/proc/sys/net/ipv4/ip\u local\u port\u range
如果您希望进行高频交换,不连续打开和关闭套接字似乎是一个不错的计划。