Developing network-based multiplayer games made easy
▲ 14 r/madeinpython+2 crossposts

Developing network-based multiplayer games made easy

Implementing network-based multiplayer games is a challenge. At the same time, game development has always been a popular choice among beginners.

For this reason I have developed a lightweight server and framework for turn-based multiplayer games. It was primarily designed for a programming course where students work on projects in small groups. However, the use of the server is not limited to educational scenarios.

  • Implementing clients is easy thanks to a user-friendly API.
  • Adding new games is accomplished by deriving from a base class and overriding its methods.

Here is a short demo of the API usage:

from game_server_api import GameServerAPI, IllegalMove

game = GameServerAPI(server='127.0.0.1', port=4711,
                     game='Yahtzee', session='mygame', players=3)

my_id = game.join()   # start/join a session
state = game.state()  # returns a dictionary

while not state['gameover']:
    # print game board here

    if my_id in state['current']: # my turn
        pos = None
        # read user input here

        try:
            game.move(position=pos) # perform a move (**kwargs)
        except IllegalMove as e:
            # something went wrong
    else:
        # opponent's turn

    state = game.state()

# end of game

It's open source: https://github.com/feberts/python-game-server

github.com
u/tio-fabi — 5 days ago

TLS: Wrap socket before or after accepting a connection?

You can use a TLS wrapper to turn a regular socket into a TLS socket. Should this be done before or after accepting a connection? Are there situations where you would prefer one approach over the other?

Below examples both work. In the first example, the socket is wrapped before a client connects:

import socket
import ssl
import threading

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile='cert.pem', keyfile='key.pem')

# create a generic socket:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.bind(('localhost', 4711))
    sock.listen()
    # wrap socket (returns a generic ssl socket):
    with context.wrap_socket(sock, server_side=True) as ssl_sock:
        while True:
            # accept connection (returns a new connection socket):
            conn, addr = ssl_sock.accept()
            threading.Thread(target=handle_connection, args=(conn, addr), daemon=True).start()
            # (close socket in thread function)

Here, the socket is wrapped only after a client has connected:

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile='cert.pem', keyfile='key.pem')

# create a generic socket:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.bind(('localhost', 4711))
    sock.listen()
    while True:
        # accept connection (returns a new connection socket):
        conn, addr = sock.accept()
        # wrap socket (returns an ssl socket):
        ssl_conn = context.wrap_socket(conn, server_side=True)
        threading.Thread(target=handle_connection, args=(ssl_conn, addr), daemon=True).start()
        # (close socket in thread function)

Are there any benefits or drawbacks to either of these approaches?

reddit.com
u/tio-fabi — 3 months ago