Simplest way to consolidate multiple socket connections into “messages”

Viewed 13

I’m trying to write a multiplayer card game for a friend. I want to make it simple enough that they (who are new-ish to Python) can easily understand the code, while still being fully featured.

I would like to have multiple clients connecting to the server, and it was my idea to send “messages”, which are JSON. As the messages arrived, they were appended to an “ID”, and then put in a queue, which is a list. The game engine code could just pop off messages, process them, and then append messages to the outgoing queue.

I was wondering what the easiest way to implement this would be, or if there is a simpler way I should be considering.

I’ve seen some people using socketserver, others using asyncio, and some people using threading.

1 Answers

I figured out a possible solution, using asyncio:

import asyncio
import json

outgoing = asyncio.Queue()
incoming = asyncio.Queue()

async def handle_incoming(reader):
    buffer = ""
    while True:
        buffer += (await reader.read(1)).decode('utf-8')
        if '\r\n' in buffer:
            packet, buffer = buffer.split('\r\n', 1)
            message = json.loads(packet)
            await incoming.put(message)

async def handle_outgoing(writer):
    while True:
        message = await outgoing.get()
        packet = json.dumps(message) + '\r\n'
        writer.write(packet.encode('utf-8'))
        await writer.drain()

async def handle_client(reader, writer):
    asyncio.create_task(handle_incoming(reader))
    asyncio.create_task(handle_outgoing(writer))

async def main():
    # This is where you would do your main program logic
    while True:
        print(await incoming.get())

async def run_server():
    asyncio.create_task(main())
    server = await asyncio.start_server(handle_client, 'localhost', 15555)
    async with server:
        await server.serve_forever()

asyncio.run(run_server())
Related