Networking recv.from Question

.blend attached; made for/with 2.57b.

Working hard on learning the GE I’ve hit yet another brick wall, trying to learn networking.

This blend is meant to be run in a terminal. After starting the engine I use a python script to send UDP packets of text to 127.0.0.1:5000. I tried

data, address = server_socket.recvfrom(256)

now commented out, which of course only lets the engine run while receiving a signal. At least it printed the received packets. I could run the blend, the cube would hang in the air but when I sent something like “Hello World” to 127.0.0.1:5000 it printed that in Blender’s terminal, and the cube was allowed to fall for a split second before the script came back.

Now I’m using the try/except bit. All I want for now is this:
I start blender
The script runs, listening but not interfering.
When it receives an arbitrary string on UDP 127.0.0.1:5000 it fires up a … any will do but let’s say a Motion actuator on the cube. Nice and simple.

Help me Blender-wan Kommunity, you’re my only hope.

Attachments

TEST.blend (457 KB)

As far as I remember you need to use the unblocking mode. As I do not care networking very much, I can’t directly help.

You might better look into the other networking threads here or in the resource forum. Also WSAG should tell you how to do it. There is a large tutorial on it.

Thanks Monster. I’ve read a lot of threads and tutorials but I just can’t seem to ‘get it’. Plus most are written for 2.49 which means I have to worry about translating them to the new API.

I may be wrong, but your trying to call socket_server as a global variable, but you haven’t defined it as such…

You called:

data, ip = bge.logic.server_socket.recvfrom(256)

should be

data,ip = server_socket.recvfrom(256)

@agoose77: That makes sense, and it’s cleaner. It seems to work the same.

does it work though?
could you upload your code for the server?

Yeah. This code is in the blend file, running off a pulsing Always sensor on the default Cube. The Cube is Dynamic, positioned above a groundplane. I can tell if python is locking up the GE by whether the cube falls or not.

import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("127.0.0.1", 5000))
print("UDPServer Waiting for client on port 5000")
#data, address = server_socket.recvfrom(256)

try:
	data, ip = server_socket.recvfrom(256)
	print(data)
except:
	pass

It freezes the GE.

This is the separate script I run in a terminal

import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket.bind(("127.0.0.1", 5002))
client_socket.setblocking(0)
client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
while 1:
	data = input("Type something(q or Q to exit): ")
	if (data != 'q' and data != 'Q'):
		client_socket.sendto(data.encode(), ("localhost",5000))
	else:
		break
client_socket.close()

I was just experimenting with other ports, and sending on port 5002 gets a reaction from the GE, even though script 1 is listening on port 5000. The first script starts immediately, so the 3D window doesn’t even refresh; it looks like the Blender UI but the mouse cursor is gone. Then I send anything on 5002 with the second script and the 3D window refreshes!

My goal is still a simple modification of script 1 so it listens but doesn’t freeze the engine. It needs to accept packets when they come, and then react however I want it to.

I’ve read lots of difficult to read tutorials written for 2.4x that make it sound like you just copy and paste their code and it all works, but it never works. So I’m trying to work it out myself, so I have full control of it. Unsuccessfully so far :stuck_out_tongue:

Anyway, I appreciate everyone’s help a lot.

It freezes because you haven’t setblocking(0)
Setblocking toggles whether the script waits untill it receives a packet. You don’t need to use the try statement unless you use setblocking(0)

type
server_socket.setblocking(0)
after
server_socket.bind((“127.0.0.1”, 5000))

YES! Thank you so much, that’s it exactly. Now on to the next problem :slight_smile:

Every time the script runs (which is a lot, it’s attached to a true-pulsing Always sensor) it prints this message:


Python script error - object 'Cube', controller 'And#CONTR#1':
Traceback (most recent call last):
  File "Text", line 3, in <module>
socket.error: [Errno 98] Address already in use

The server script is not running though. It does this for whatever port I choose.

Thanks for your patience, I’m sure these questions are really simple to all the pros.

You should make a function around of the try statement and call it as a module. Now You open and bind the socket on every run - that probably not good.

@LaH: That’s a good suggestion. Now I’m using this code


import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("127.0.0.1", 5000))
server_socket.setblocking(0)

print("UDPServer Waiting for client on port 5000")
def receive():
	data, ip = server_socket.recvfrom(256)
	print(data)

and using receive() as a module. You can see it in the attached blend.
The two errors I receive are 98, Address already in use, and 11, Resource temporarily unavailable. I get these no matter what port I use. Still working on figuring out what exactly I’ve done to my poor network interface.

Attachments

TEST.blend (454 KB)

Okey dokey.


import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("127.0.0.1", 5000))
server_socket.setblocking(0)

print("UDPServer Waiting for client on port 5000")
def receive():
	try:
		data, ip = server_socket.recvfrom(256)
		print(data)
	except:
		print("no data")
		pass


Errno 11 comes when the socket is in nonblocking mode and no data is received. So reimplement the try/except and it goes away.

EDIT:
And now the server script gets

socket.error: [Errno 98] Address already in use
So they both can’t be connected to the same port at the same time. Can’t you recvfrom a port without binding to it?

EDIT:
You can just send signals.

Ok, It seems to be listening, but it doesn’t receive any packets on 5000, and I tested that other programs can.

Right, firstly You MUST have try and except statements if setblocking is set to 0.
This is because if you enable blocking (1) then it waits until receiving a signal until it continues the code.
This is why the GE appears to freeze.
With setblocking(0) it doesn’t wait to receive, and thus throws an error when it doesn’t receive data.
Also, the game engine will often run the script once, but if you quit the Game Engine and play it again, it doesnt end the socket instance, and so it says the socket is in use.
What i recommend you do is:
1)Choose a high port number.
2)Bind the connection
3)Make a sensor to the script so that when you press ESC, it runs a function and activates the end game actuator:

if end.positive:
     server_socket.close()
     controller.activate(endgame)

obviously you must define the sensor and actuator names.
4)You don’t have to print the data in the try statement.
Instead you can use it to execute another function…

def receive():
	try:
		data, ip = server_socket.recvfrom(256)
	except:
		data = False
		pass
	if data != False:
		print(data)

That works great! Thanks a ton agoose77. Now I can start certain actuators via network.
Great suggestion, about closing the port with an Keyboard ESC sensor.

No worries, i use it all the time in my networking component!