Search code examples
socketsnetwork-programmingudpgame-engineportforwarding

How do game clients receive UDP data from server?


What I wanted to do:
For learning about game programming I created an echo setup using a dedicated server and UDP. The dedicated server is in a different city (aka NOT in my local network).

On my local computer I have a udp client and server ( 2 different programs ). When I first started my python server I was immediately asked by windows firewall whether I want to add an exception. After allowing networking for my python server, I still did not receive any messages. (client -> dedicated server -/-> local server )
Only after I set a port forwarding in my router I was able to receive messages on my local UDP server.

My question is:
How do games solve that problem ? I don't activate a port forwarding for each multiplayer game I want to play and I'm still able to receive data in all these games.

My dedicated server setup (address and port intentionally changed):

#!/usr/bin/python3

import socket

ADDRESS = "1.123.123.123"
PORT = 12345

serverSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSock.bind((ADDRESS, PORT))

clientSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

addresses = []

while True:
    data, addr = serverSock.recvfrom(1024)
    if addr not in addresses:
        addresses.append(addr)
    msg = str(data)
    #if msg.split()
    print("Message: " + str(data))
    outMsg = str(addr) + ":" + msg
    for ad in addresses:
        print("Send Msg " + outMsg + " to " + ad[0] + ":" + str(PORT))
        clientSock.sendto(bytes(outMsg, "utf-8"), (ad[0], 12345))
    print("Addresses: " + str(addresses))

Solution

  • I figured this one out while writing up the question (like talking to the good old rubber duck):

    The trick is not using 2 programs on the local computer. The program that sends the message also needs to retrieve the message. In my example it's blocking calls (ugly!), for a game you'd want to make that asynchronous. But this is the simplest way to get around the router firewall:

    #! /usr/bin/python3
    
    import socket
    
    ADDRESS = "1.123.123.123"
    PORT = 12345
    
    clientSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     # usually not required to bind a client, but we want to receive messages
    clientSock.bind(("0.0.0.0",PORT))
    
    while True:
        msg = input("Enter message: ")
    # Note that it is not required to send to the same port 
    # you have locally binded to.
        clientSock.sendto(bytes(msg, "utf-8"), (ADDRESS, PORT))
    # listen to the echo:
        data, addr = clientSock.recvfrom(1024)
        print(str(data) + " from " + str(addr))
    

    However, my understanding on sockets and firewalls is limited. I do not understand why THIS works but 2 separated programs don't. Maybe someone could comment on that. Hope I can save someone some time =)