Running Game Engine while reading data wirelessly

I have a Blender code which takes sets of data from a csv file and uses them to rotate a robot arm and a human model in the Game Engine. This code works fine, but now I want to send data across a wireless connection to Blender.

I have a server code set up in Blender (which runs on Python 3)


# Server Program
# Make sure the client is being run on the data generation computer

SERVER_LOOP = True

import socket
import sys
import json
import bge


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

print ('INFO: Starting up')

# Create a TCP/IP socket to listen on
print ('INFO: Creating TCP/IP Socket')
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Prevent from 'ADDRESS ALREADY IN USE' upon restart
print ('INFO: Housekeeping...')
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# Bind the socket to port 8081 on all interfaces
server_address = ('localhost', 8081)
print ('INFO: Binding and starting up on %s port %s' % server_address)
server.bind(server_address)
print ('INFO: Server bound')

def send_welcome(cont):
        cont.send('SERVER: Welcome'.encode('utf8'))

# Listen for connectons for 5 seconds
server.listen(5)

# Connection is the SOCKET OBJECT for the connection
# Client_address is the connected peer(the client)
connection, client_address = server.accept()
print ('INFO: Connection from', connection.getpeername())
print ('INFO: Sending welcome msg')
send_welcome(connection)
print ()
        
while SERVER_LOOP:

        # Receive data
        try:
            data = connection.recv(10000)
                
        # Unless there's an error
        except OSError:
            print (connection)
        
        # Decode the data into usable lists
        if type(data) != type(''): 
            data = data.decode()
        
        # If we want to end the client stream but keep the server running    
        if data=='end' or data=='End' or data=='END':
            print ('INFO: Closing connection with ',connection.getpeername())
            connection.shutdown(socket.SHUT_RD | socket.SHUT_WR)
            print ()
            connection.close()
            connection, client_address = server.accept()
            print ('INFO: Connection from', connection.getpeername())
            print ('INFO: Sending welcome msg')
            send_welcome(connection)
            print ()
                
        # If we want to stop running the server
        elif data=='end server' or data=='End server' or data=='End Server':
            print ()
            print ('SERVER SHUT DOWN')
            SERVER_LOOP = False
        
        # Display when data is loaded back on the client side
        else:
                # gives feedback in server command line
                data = json.loads(data)
                owner['test'] = data
                print ('CLIENT: %s' % data)
                message = 'ping'
                connection.send(('SERVER: %s' % message).encode('utf-8'))
                print ('SERVER: %s' % message)

And the client code to run with it (this one runs on Python 2.7)

# Client Program
# Make sure the server is being run in Blender

import socket
import time
import json

print 'INFO: Creating Socket'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

ip_addr = raw_input('IP: ')
port_addr = raw_input('PORT: ')

# Type 'localhost' in the IP field
# Type '8081' in the PORT field

print 'INFO: Connecting to server'
s.settimeout(5) # Times out if 5 seconds without connecting to client
s.connect((ip_addr, int(port_addr)))

# Listen for welcome
data = s.recv(10000)
print data
print ''
while 1:
        message = raw_input('CLIENT: ')
        if message=='end' or message=='End' or message=='END':
                print ''
                print 'SHUTTING DOWN CLIENT, SERVER STILL RUNNING'
                s.send(message)
                break
        elif message=='end server' or message=='End server' or message=='End Server':
                print ''
                print 'SHUTTING DOWN SERVER'
                s.send(message)
                break
        else:
                s.send(message)
                data = s.recv(10000)
                print data

print 'INFO: Closing socket'
s.close()
print 'INFO: Quitting'


Now, obviously this doesn’t do the rotations; it’s just a test script to make sure that the data transfer between the two works. And it does - in Blender’s system console, the data is displayed just as I want it. However, I have a string debug property in Blender titled “test”, which is supposed to display the current number just typed in the client, and it’s not until I close the whole program down.

For example:

  • I run the server script in Blender
  • I run the client script in IDLE
  • I type in numbers on the client side
  • They appear in the system console on the server side, but they do NOT appear in the Game Engine
  • I close the server from the client side
  • Now, the last number I typed finally appears on the server side

So the problem is that Blender runs my script and then the Game Engine after it’s done, but I want them to run concurrently.

Let me know if my explanation doesn’t make sense; I can provide downloads to my stuff if need be.

Thanks for the suggestions. I think that making the sockets non-blocking is the way that I want to use. I tried putting in “server.setblocking(0)” after the line “server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)” and it returned the error: “A non-blocking socket operation could not be completed immediately”. From what I understand in your code in the other thread, this is where the “except socket.error” comes in, as it waits until the client wants to send data. I was unable to run your sample code since it also prompted an error, so I don’t know what to do to remedy my setblocking problem.

You are correct, that error is an “expected exception” when the socket is in non-blocking mode. Any call that would normally block needs to be wrapped in a try-except block and then you check for this error code and ignore it. All other errors should be handled in the usual manner.

I believe that you will need to wrap any “accept()”, “recv()” and “write()” calls. You will notice that when you call ‘accept’ one of the returns is another socket object. You will need to set this into non-blocking mode as well.

I added some loops around the “connection, client_address = server.accept()” and “data = connection.recv(10000)” lines so now the errors are not occurring. However, the game engine still is not running at the same time as the server code. I attached my blender file so you can check it out. The client is the same one from my first post. Just run it in IDLE or something. The game engine doesn’t start up until there’s an error or the server is ended. I just don’t know exactly what will let both run simultaneously.

server.blend (425 KB)

1)In your client script all print statments are wrong. You must add parenthesis.
2)raw_input() was renamed to input() in Python v3.
To get the old behavior of input(), use eval(input())
3)After this correction the client have received the string b’SERVER: Welcome’
4)Another problem is on server script that block for ever Blender ( on my pc windows 7)
5)On the client and on the server script I was also obliged to change the number port to ‘80’

As I said in the original post, the client code runs in Python 2.7, where the syntax is different from 3.3
This was just for simplicity’s sake.

The loops that you added are now blocking Blender instead of the socket calls. You have to catch the exceptions and if it is a “would block” exception then you just exit your script. You tie your script to an ‘Always’ sensor and check for socket connections, reads, and writes once a frame.

Check out the attached ZIP file. It contains a .blend and a simple implementation of a TCP server and client.

Running

  • Open an instance of blender with a Console. Under Windows you can just run Blender then do “Help->Toggle System Console” but I think you have to jump though hoops on Mac and Linux.
  • Hit ‘P’ to play the game
  • Hit ‘S’ to start the server. You will see a note in the console that the server is starting

You will see that there is a very simply tumbling cube. That is just there to show you that the game engine is not frozen.

  • Open a 2nd instance of Blender. This one does not need the console.

  • Hit ‘P’ to play the game

  • Hit ‘c’ to send a client message from the 2nd instance to the first.

  • In the first instance’s console you will see the message received from the client and some status information from the server.

Server Implementation Details

There is an empty called “server_empty” with an ‘always’ and a ‘keyboard’ sensor on it. When you hit ‘s’, the keyboard sensor fires and allocates and starts a server object in listening mode then exits.
The ‘always’ sensor fires once a frame and checks to see if there are clients to connect or any clients that it is currently tracking. If there are clients it is tracking it also tries to read data from them. All this is done in non-blocking mode and the function exits after it has checked everything.

Client Implementation Details

There is an empty called “client_empty” with an ‘always’ and ‘keyboard’ sensor on it. When you hit ‘c’, the keyboard fires and allocates a client object and attaches it to the Empty. It inits the object to try to send a message to a given host+port.
The ‘always’ sensor fires once a frame and if there is a client trying to send a message, it tries to send it. If the message is sent, then it close the client and clears the client property.

More fun you can have

The server can track multiple client connections at the same time, but it is kind of overkill here because the clients close their connection as soon as they have sent a very short message. A full implementation would keep the connection alive to enable sending + receiving data.

The ‘StreamClient’ object is very sparse. In a full implementation, you would add a way to queue messages to send and queue received messages and the client would just send them as quickly as it could.

Attachments

bgeServer.zip (68.1 KB)

Thanks. If I want to add in a raw input prompt, like in my script, would I use the startClient module and replace the “Test Message” with that? I’ve tried a few methods using the input() command, but they just freeze up Blender like before. Is using that command not the right approach?

EDIT: Wait, a minute, it only seems to freeze up the client Blender instead of the Server one. That’s fine! I need to do some fiddling around here…

If you want to send arbitrary data from the client to the server without freezing the client then the high-level changes you need to make are:

  • in the “TCPServer.Client” object:
    • Add a list of data buffers that the object tries to send
    • Remove the logic that closes the connection after it sends a message
    • Each frame, check to see if there is any data to send. If there is no data, then just exit. Otherwise send some data and track
      how much was sent.

The whole point of the non-blocking code is that you tell the system, “try to send this data and if you can’t then let me know.” When the system says that it cannot send data then you just exit your routine. You get another shot on the next frame. That is what keeps the engine from freezing.

This seems like a fairly simple question, but how do you store the data that’s being printed by the server as a variable that can be used in a separate function defined within the server? I’ve gotten the raw input to work now.

Normally, I would define some structured message that the client and server send over the socket. It can be as simple as sending a byte that represents the ‘type’ of message, then an int that is the length of the message, then a raw byte[] that is the message itself. Then you know what kind of message and how much data you need to receive before you can fully decode the message.

Types of messages might be ‘chat’ then the message body is just a string, ‘position update’ and the message is an object and a location, etc.

I would accept these messages then put them into a list inside the Server. Just like it has a list of clients that are connected, it would have a list of received messages. Then you can have a method in the server that processes the messages. So it would iterate the received messages, process them, then empty the list out. To process a received ‘chat’ you might just display the string in a window. To process a ‘locatino update’ you might move an object to a new location, etc.