Несколько ключевых моментов о том, как заставить это работать:
- Обработка всех ваших операций ввода-вывода сокета в потоке
- Отправка События Pygame назад к основное l oop когда происходят события сокетов
- Не спите и не задерживайте ваше главное событие пигмея-l oop. Ever.
Вот пример потока Socket-Listener, который отправляет события обратно в основной поток Pygame. Приношу свои извинения за длину кода, но я хотел ответить чем-то полным.
import threading
import pygame
import random
import enum
import socket
import select
import time
### Event types that are sent to the main event loop
class NetworkEvents( enum.IntEnum ):
EVENT_HANGUP = pygame.USEREVENT + 1
EVENT_COMMAND = pygame.USEREVENT + 2
### Socket-listener thread that reads commands from the server
### and does the parsing and posting of commands to the main event-loop
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 ) )
break;
except:
print( "Failed to connect %s:%d, will retry" % ( self.server_address, self.server_port ) )
time.sleep( 12 )
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.5 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 command in self.data_buffer.split('\n'):
command = line.strip()
# client disconnect command
if ( command == '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 ( command in ( 'red', 'green', 'blue' ) ):
new_event = pygame.event.Event( NetworkEvents.EVENT_COMMAND, { "address" : self.server_address, "message" : command } )
pygame.event.post( new_event )
self.data_buffer = '' # all used-up
### MAIN
# Start the connection-listener thread
thread1 = ConversationHandlerThread( '127.0.0.1', 5555 )
thread1.start()
После запуска потока события принимаются в основном l oop, так же, как любое другое событие PyGame:
# Main paint / update / event loop
done = False
while ( not done ):
SPRITES.update()
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_COMMAND ):
print(" CLIENT MESSAGE FROM %s - %s " % ( str(event.address), event.message ) )
if ( event.message == 'red' ):
new_sprite = AlienSprite( RED )
SPRITES.add( new_sprite )
# ... etc.
Если ваш ввод-вывод сокета обрабатывается в потоке, а главное событие -l oop никогда не спит, вы должны иметь возможность создавать хорошо работающую программу с PyGame. Сделайте свой сетевой трафик c маленьким и лаконичным.