BGE 2.79 working network Game/Example - Who has?

Does anyone have a working server / client script for BGE 2.79? If so, could you share it?

Catching up the internet, I managed to create something simple:

server.py

import bgeimport socket
import pickle


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(('', 10000))
s.setblocking(0)
s.listen(1)


controller = bge.logic.getCurrentController()
player = controller.owner


while True:
    
    connection, client_address = s.accept()
    
    try:
        data = connection.recv(4096)
        UPData = pickle.loads(data)


    finally:
        player.worldPosition[0] = UPData[0]
        player.worldPosition[1] = UPData[1]
        player.worldPosition[2] = UPData[2]
        connection.close()

client.py

import socketimport pickle
import bge


# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


# Connect the socket to the port where the server is listening
server_address = ("", 10000)
sock.connect(server_address)


cont = bge.logic.getCurrentController()
player = cont.owner


data = []
data.append(player.worldPosition[0])
data.append(player.worldPosition[1])
data.append(player.worldPosition[2])


UPData = pickle.dumps(data)
sock.sendall(UPData)

The problem is that when I run server.py and it crashes me:

OSError: [Errno 98] Address already in use

Lsof -i: 10000 check what it uses and it is blender

Has anyone encountered this problem ??

Your code in essence should work the first time you run it.

But as the BGE and Blender share the same Python VM instance, when you open a socket on say, host(localhost, 10000) Python asks the OS to hand him a socket. The thing is I don’t see anything to close and free the socket back, so what must happen is that as long as you don’t restart the Python VM the unclosed socket will exist (just restarting Blender should do the trick).

Secondly and importantly, you are doing a “while True”, this will freeze the BGE.

The BGE is already doing some kind of “while True” by itself: rendering frame, executing logic and scripts, repeat.
So you should adapt your scripts/modules to harvest the BGE mainloop instead of executing your own infinite while loop.

Know that you could in theory use threads to run a while loop, but trust me when I say this would bring more trouble than trying to run just one iteration of your loop per frame.

I always open socket only once like:


import bge
import socket
import pickle

controller = bge.logic.getCurrentController()
player = controller.owner

if not 'socket' in player:
    player['socket'] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    player['socket'].bind(('', 10000))
    player['socket'].setblocking(0)
    player['socket'].listen(1)

try:
    connection, client_address = player['socket'].accept()    
    data = connection.recv(4096)
    UPData = pickle.loads(data)
    player.worldPosition[0] = UPData[0]
    player.worldPosition[1] = UPData[1]
    player.worldPosition[2] = UPData[2]

except:
    pass

Then you don’t need to open it and close every frame.

Thanks … Finally it started working as it should :wink:

Error handling

Never ever catch ALL errors. You will loose a lot of hairs because of that.
Even more ripped off hairs: you silently ignore ANY error by not dealing with them (pass).

Better write down the errors that you expect. Ignoring them is an option. Be sure it is your option rather then a “because it works [right now]” situation.

Polling

Hint: socket has a non-blocking mode

Another important thing to note: in your example you are using the pickle module to interpret the received data from the client. This is fine if you’re just testing things internally, but if you ever intend to distribute your code you should absolutely NOT use pickle when receiving data from clients!

The pickle module is not secure (read the big red warning at the top of the pickle module’s documentation). A malicious client can send specially crafted data that would cause the receiving client/server to run arbitrary code when they attempt to un-pickle the data. This means an attacker could gain access to your user files, install key-loggers, steal data, etc. If you run your game as an administrator, the attacker could even take control of your entire computer.

If you ever intent to share you game/code, you should handle serializing/de-serializing the data yourself and not rely on the pickle module.

For this matter I don’t know about the current state of art about this, but I would consider using this module:
https://docs.python.org/3/library/struct.html

You can send wrong data, but it will never get out of the format you specify, nor execute code from nowhere.

Speaking of which… I wrote this awhile back: https://github.com/pqftgs/python-serializer
It’s a serialization library for games that uses struct behind the scenes. Supposedly easy to use, but it’s not maintained these days.

Hope it helps.