Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/maven/5.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_C_Sockets_Server_Frequency - Fatal编程技术网

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

我在localhost上有一个用c运行的服务器。 我不确定在这里显示相关代码是否有意义(它是从中得到强烈启发的)

在同一台机器上,我有一个python客户端,其代码如下:

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端。我想这样做的副作用是,只有一个客户机可以连接到服务器,但这符合我的需要

python客户端进程正在创建多少套接字?如果您使用的是linux系统,您可以执行类似于
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
如果您希望进行高频交换,不连续打开和关闭套接字似乎是一个不错的计划。