Python 多人游戏中的Pygame和socket:OverflowError
我正在尝试使用Python 多人游戏中的Pygame和socket:OverflowError,python,python-3.x,multithreading,sockets,pygame,Python,Python 3.x,Multithreading,Sockets,Pygame,我正在尝试使用pygame和socket模块在Python中创建一个简单的多人游戏。它只是由两个圆圈组成,由两台不同计算机的W、A、S、D键控制 起初,我在PyGod循环的中间创建了一个带有 ReVo()/Client的客户端。它工作得很好,但是recv()阻塞了环路,因此圆圈的移动不平稳,我必须将速度增加到6(在设置为0.6之前),以获得正常速度。这是代码(我已经对其进行了一些总结): 客户端第1版 然后,我尝试将recv()放在一个线程中,以停止阻塞循环: 客户端第二版 但是,当我在两台不同
pygame
和socket
模块在Python中创建一个简单的多人游戏。它只是由两个圆圈组成,由两台不同计算机的W、A、S、D键控制
起初,我在PyGod循环的中间创建了一个带有<代码> ReVo()/Client的客户端。它工作得很好,但是
recv()
阻塞了环路,因此圆圈的移动不平稳,我必须将速度增加到6(在设置为0.6之前),以获得正常速度。这是代码(我已经对其进行了一些总结):
客户端第1版
然后,我尝试将recv()
放在一个线程中,以停止阻塞循环:
客户端第二版
但是,当我在两台不同的计算机上启动客户机2的两个实例时,它会给我一个溢出错误
:
溢出错误:Python int太大,无法转换为C long
我为范围(30)中的I添加了:
,因为我认为服务器正在崩溃,因为同时发送的消息太多了。输出是相同的:大约3秒钟后,程序崩溃,出现溢出错误
在两个版本中,我都在recv()
之后添加了print()
语句,以查看我接收到的x和y的值。在第1个版本中,它们都在宽度和高度范围内。然而,在第二个版本中,收到的消息中有1/5是一个大数字,例如124381473265
。如果此数字更大,则会出现溢出错误。我不明白为什么会发生这种情况:我在两个版本中以相同的方式编码和解码消息,但一个有效,另一个无效
我没有包括服务器代码,因为我认为没有必要。它只是在两个客户端之间传输消息,而不修改它们。服务器没有出现错误,因为在第一个客户端版本中,消息的发送和接收都是正确的
任何帮助都将被告知。如果你需要关于任何一点的更多信息,请告诉我
提前谢谢 将套接字代码放入线程,或使用select.select()
进行非阻塞套接字读取。然后,当数据报从服务器到达时,将自定义事件消息发回主循环
import pygame
import enum
class NetworkEvents( enum.IntEnum ):
EVENT_HANGUP = pygame.USEREVENT + 1
EVENT_MESSAGE = pygame.USEREVENT + 2
您的套接字读取代码也应该处理部分数据包、挂起和延迟。我认为你上面的错误是由于试图打开一个部分(或某种程度上是垃圾)数据包造成的。人们通常使用pickle
模块来封装这些数据,但首先,我会使用简单的字符串数据进行预测试。它更容易调试。然后,一旦传输代码全部固定下来并经过测试,如有必要,将其更改为二进制
我喜欢在套接字代码中使用select()。它提供了对套接字的细粒度控制
下面是一个简单的线程套接字对话处理程序。它实际上只支持套接字挂起和传入消息。但它可以很容易地扩展以处理更多的消息类型
import threading
import pygame
import random
import enum
import socket
import select
import time
class ConversationHandlerThread( threading.Thread ):
""" A thread that handles a conversation with a single remote server.
Accepts commands of 'close', 'red', 'green' or 'blue', and posts messages
to the main PyGame thread for processing """
def __init__( self, server_address, server_port ):
threading.Thread.__init__(self)
self.server_address = server_address
self.server_port = server_port
self.server_socket = None
self.data_buffer = ''
self.daemon = True # exit with parent
self.done = False
def stop( self ):
self.done = True
def connect( self ):
self.server_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
while True:
try:
self.server_socket.connect( ( self.server_address, self.server_port ) )
print( "Connected to %s:%d" % ( self.server_address, self.server_port ) )
break;
except:
print( "Failed to connect %s:%d" % ( self.server_address, self.server_port ) )
time.sleep( 12 )
print( "Retrying..." )
def run( self ):
""" Connects to Server, then Loops until the server hangs-up """
self.connect()
# Now we're connected, start reading commands
read_events_on = [ self.server_socket ]
while ( not self.done ):
# Wait for incoming data, or errors, or 0.3 seconds
(read_list, write_list, except_list) = select.select( read_events_on, [], [], 0.5 )
if ( len( read_list ) > 0 ):
# New data arrived, read it
incoming = self.server_socket.recv( 8192 )
if ( len(incoming) == 0):
# Socket has closed
new_event = pygame.event.Event( NetworkEvents.EVENT_HANGUP, { "address" : self.server_address } )
pygame.event.post( new_event )
self.server_socket.close()
self.done = True
else:
# Data has arrived
try:
new_str = incoming.decode('utf-8')
self.data_buffer += new_str
except:
pass # don't understand buffer
# Parse incoming message (trivial parser, not high quality)
# commands are '\n' separated
if (self.data_buffer.find('\n') != -1 ):
for line in self.data_buffer.split('\n'):
line = line.strip()
# client disconnect command
if ( line == 'close' ):
new_event = pygame.event.Event( NetworkEvents.EVENT_HANGUP, { "address" : self.server_address } )
pygame.event.post( new_event )
self.server_socket.close()
self.done = True
# only make events for valid commands
elif ( line in ( 'red', 'green', 'blue' ) ):
new_event = pygame.event.Event( NetworkEvents.EVENT_MESSAGE, { "address" : self.server_address, "message" : line } )
pygame.event.post( new_event )
self.data_buffer = '' # all used-up
把所有这些复杂的东西放到一个线程中的美妙之处在于,一旦它开始了,你就可以忘记它
# Start the network-handler thread
thread1 = ConversationHandlerThread( '127.0.0.1', 5555 )
thread1.start()
在主循环中,像处理其他事件一样处理事件:
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == NetworkEvents.EVENT_HANGUP ):
print(" CLIENT DISCONNECTED %s " % ( str(event.address) ) )
elif ( event.type == NetworkEvents.EVENT_MESSAGE ):
print(" CLIENT MESSAGE FROM %s - %s " % ( str(event.address), event.message ) )
if ( event.message == 'red' ):
new_sprite = AlienSprite( RED )
SPRITES.add( new_sprite )
# Start the network-handler thread
thread1 = ConversationHandlerThread( '127.0.0.1', 5555 )
thread1.start()
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == NetworkEvents.EVENT_HANGUP ):
print(" CLIENT DISCONNECTED %s " % ( str(event.address) ) )
elif ( event.type == NetworkEvents.EVENT_MESSAGE ):
print(" CLIENT MESSAGE FROM %s - %s " % ( str(event.address), event.message ) )
if ( event.message == 'red' ):
new_sprite = AlienSprite( RED )
SPRITES.add( new_sprite )