基于Python Socket的卡牌应用服务器代码技术咨询
Let's break down your card game socket code and walk through actionable improvements, potential pitfalls, and best practices to make it more robust and maintainable:
1. Reduce Redundant Code with Helper Functions
Your current logic for sending card updates to players repeats almost identical code for p1 and p2. Following the DRY (Don't Repeat Yourself) principle, extract this into a reusable function to clean up your loop and make future changes easier:
import random import pickle def send_card_update(p1_conn, p2_conn, card, is_hakem_p1): # Craft messages for each player p1_msg = f"{card} for {'you' if is_hakem_p1 else 'other'}" p2_msg = f"{card} for {'other' if is_hakem_p1 else 'you'}" # Send serialized messages p1_conn.send(pickle.dumps((p1_msg, False))) p2_conn.send(pickle.dumps((p2_msg, False))) # Updated main loop while temp_deck: # Stop loop when deck is empty (prevents infinite loop!) c = random.choice(temp_deck) temp_deck.remove(c) # Use the helper function instead of duplicate if/else blocks send_card_update(p1, p2, c, hakem == p1)
2. Complete & Consistent Hakem Announcements
Your code cuts off when handling Ace cards—make sure both players get clear, consistent notifications about who becomes the Hakem. Also, double-check if you need to update the hakem variable here (since drawing an Ace likely assigns the role):
if c in ['A♠','A♣','A♦','A♥']: is_hakem_p1 = hakem == p1 # Send role notifications if is_hakem_p1: p1.send(pickle.dumps(('You are Hakem!', False))) p2.send(pickle.dumps(('Opponent is Hakem!', False))) else: p1.send(pickle.dumps(('Opponent is Hakem!', False))) p2.send(pickle.dumps(('You are Hakem!', False))) # Optional: Update hakem to the new holder if drawing an Ace assigns the role # hakem = p1 if is_hakem_p1 else p2
3. Critical Security & Stability Fixes
- Avoid Pickle for Socket Communication:
pickleis unsafe for network use—it can execute arbitrary code when unpickled by a malicious client. Switch to a safe format like JSON instead:import json # Send message with JSON p1.send(json.dumps({"message": p1_msg, "is_action": False}).encode('utf-8')) # Client-side receive example data = json.loads(conn.recv(1024).decode('utf-8')) message = data["message"] is_action = data["is_action"] - Handle Player Disconnections: Wrap socket sends in try/except blocks to catch errors like broken connections, and notify the remaining player:
try: p1.send(pickle.dumps((p1_msg, False))) except (ConnectionResetError, BrokenPipeError): # Notify player 2 of the disconnect p2.send(pickle.dumps(('Opponent disconnected! Game over.', True))) break # Exit the game loop - Use Threading for Concurrent Games: If you plan to support multiple game sessions at once, your current loop will block. Use
threadingto run each game in a separate thread, orasynciofor async socket handling.
4. More Efficient Deck Management
Instead of using random.choice() + remove() (which is O(n) time per card), shuffle the deck once and pop from the end—this is faster and cleaner:
# Initialize and shuffle deck once at game start temp_deck = ['A♠','A♣','A♦','A♥', '2♠', '2♣', ...] # Full deck list random.shuffle(temp_deck) # Draw cards from the shuffled deck while temp_deck: c = temp_deck.pop() # Takes last card (O(1) operation) send_card_update(p1, p2, c, hakem == p1) # Rest of your logic
内容的提问来源于stack exchange,提问作者Nemexia

