Python Socket 报错 "[Errno 24] 打开文件太多

7 投票
2 回答
22741 浏览
提问于 2025-04-19 21:49

我有一个UDP类,每秒大约发送100次数据数组。

from six import string_types
import socket
import struct

def convert_data(iterable):
    if isinstance(iterable, string_types):
        return str(iterable)
    data = tuple(iterable)
    format = "{0}H".format(len(data))
    print("Sending data:", format, data)
    if max(data) > 2**16 - 1:
        raise ValueError(max(data))
    if min(data) < 0:
        raise ValueError(min(data))
    return struct.pack(format, *data)

class UDP(object):
    def __init__(self, ip, port):
        self._ip = ip
        self._port = port
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.connect((ip, port))

    def send_data(self, data):
        message = convert_data(data)
        return self.socket.sendall(message)

大约发送了一分钟后,它出现了以下错误,尽管之前发送成功了:

Traceback (most recent call last):
  File "take_analogue_data.py", line 13, in <module>
  File "take_analogue_data.py", line 8, in main
  File "/home/pi/nio-integration/hardware/raspi/UDP.py", line 22, in __init__
  File "/usr/lib/python2.7/socket.py", line 187, in __init__
socket.error: [Errno 24] Too many open files

我找过解决办法。这个Stack Overflow的回答建议增加可以打开的文件数量。不过我觉得这并不是我想要的解决方案。

我能做些什么呢?我在想每次关闭连接可能会有效,但我已经尝试过很多方法了。(我试过了sendsendallsendto,都没有成功。)

注意:我在树莓派上运行的是Python2.6和Raspbian Wheezy。

编辑 另一个模块正在发送数据。它可能看起来像这样:

import UDP
udp = UDP.UDP(IP, PORT)
while(True):
    udp.send_data(range(8))
    sleep(0.01)

2 个回答

1
class UDP(object):

    def __init__(self, ip, port):
        self._ip = ip
        self._port = port
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.connect((ip, port))

你需要知道的是,UDP是一种无会话和无连接的协议。这意味着你不能使用self.socket.connect((ip,int(port)))这样的方式去连接,所以你应该把它去掉。

如果你想要连接到一个服务器,应该使用TCP协议:

class TCP(object):

    def __init__(self, ip, port):
        self._ip = ip
        self._port = port
        self.socket = socket.socket() #Here is the change
        self.socket.connect((ip, port))

    def send_data(self, data):
        message = convert_data(data)
        return self.socket.sendall(message)

希望这对你有帮助!

7

很可能,你在每次循环 while(True): 的时候都在创建一个新的套接字。每个进程能打开的文件描述符数量是有限的(套接字也是文件描述符)。你可以查看 /etc/security/limits.conf 文件,看看你的限制设置是什么。

当你用完套接字后,应该把它关闭,或者更理想的做法是只打开一个套接字,然后尽量重复使用它。

你提到你的其他模块“可能看起来像这样”。那段代码片段真的是这样吗?

我对此表示怀疑,因为如果是这样的话,应该只会创建一个套接字。如果你在 while 循环里面实例化 UDP 对象,那么上面提到的问题肯定就是你的麻烦所在。

撰写回答