在Python中监听UDP数据包出错 - socket.error: [Errno 24] 打开文件过多
我刚开始学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上找到一个很好的套接字教程和一个简单的线程示例。
希望这能帮到你。