在Python中监听UDP数据包出错 - socket.error: [Errno 24] 打开文件过多

2 投票
1 回答
2457 浏览
提问于 2025-04-17 18:01

我刚开始学Python,最近遇到一个问题卡了我很久。

简单来说,我正在制作一个模块,这个模块是用在游戏里的(使用的是pygame这个模块),不过我不想通过pygame模块直接获取键盘按下的键,而是想通过网络,用UDP的方式来接收这些按键。

我创建了一个模块,它会在一个单独的线程上监听指定的UDP端口,并把按下的键返回给游戏,随时可以调用。

我写的代码运行了一段时间,但速度很慢,过一会儿就会出现以下错误信息:

Traceback (most recent call last):
  File "game.py", line 164, in <module>
  File "/usr/lib/python2.7/dist-packages/pygame/sprite.py", line 399, in update
  File "/home/globe/Desktop/Asteroids/sprites.py", line 41, in update
  File "/home/globe/Desktop/Asteroids/networkControlLatest.py", line 18, in getKeyPressed
  File "/home/globe/Desktop/Asteroids/networkControlLatest.py", line 8, in __init__
  File "/usr/lib/python2.7/socket.py", line 187, in __init__
socket.error: [Errno 24] Too many open files
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/apport_python_hook.py", line 66, in apport_excepthook
ImportError: No module named fileutils

Original exception was:
Traceback (most recent call last):
  File "game.py", line 164, in <module>
  File "/usr/lib/python2.7/dist-packages/pygame/sprite.py", line 399, in update
  File "/home/globe/Desktop/Asteroids/sprites.py", line 41, in update
  File "/home/globe/Desktop/Asteroids/networkControlLatest.py", line 18, in getKeyPressed
  File "/home/globe/Desktop/Asteroids/networkControlLatest.py", line 8, in __init__
  File "/usr/lib/python2.7/socket.py", line 187, in __init__
socket.error: [Errno 24] Too many open files

networkControlLatest.py文件的内容如下:

*****from socket import *
import threading
#Class to get key pressed UDP packet on a separate thread
class networkReceive(threading.Thread):
     def __init__(self,address):
         threading.Thread.__init__(self)
     self.address = address
     self.server_socket = socket(AF_INET, SOCK_DGRAM)
         self.server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
     self.server_socket.bind(self.address)
         self.recv_data = ''

     def run(self):
         self.recv_data, addr = self.server_socket.recvfrom(2048)

def getKeyPressed():
    address = ('129.11.148.65', 6005)
    thread = networkReceive(address)
    thread.start()
    thread.join(0.01)
        recv_data = thread.recv_data
    thread.server_socket.close()
    print recv_data
    return recv_data*****

在game.py文件中调用这个模块的一个例子如下:

keys = networkControlLatest.getKeyPressed()
        if keys == 'A':
            laser = sprites.Bullet(screen,Ship.angle,Ship.rect.center)
            bulletgroup.add (pygame.sprite.Group(laser))
            delay = 15 

游戏使用键盘时运行得很好,所以我知道问题出在网络部分,但我就是搞不清楚到底是什么问题!任何帮助都非常感谢,我已经盯着这段代码太久了……!

1 个回答

4

你每按一次键就用一个新的套接字,然后再开一个线程去获取数据。建议你在一个线程里生成套接字,把数据写入一个队列,然后在getkeyPresed()函数里从队列中读取数据。

这是我的一点建议。

编辑:正如@cfi所说,你的问题主要是因为你从来没有关闭套接字,每次调用时都重新启动一个新的。这样在你按了几次键之后,系统可用的文件描述符就会达到上限,而Python的全局解释器锁(GIL)需要在不同的线程之间切换,等待GIL设置的操作数量才能继续,即使线程在等待输入输出时也是如此。如果你想使用线程,应该了解Python中线程的工作原理,并阅读关于Python3中GIL改进的内容,以解决线程延迟的问题。对于你的问题,你应该设置一个套接字,并准备线程只接收数据。

你可以在binarytides上找到一个很好的套接字教程和一个简单的线程示例。

希望这能帮到你。

撰写回答