Networking - Need some help fixing my code

Hello guys,

I’m trying to setup a proper connection between server and client that allows the server to not only receive but also to send back data to the client.

Here’s what I have so far:
Client

import socket
import pickle
import bge

server = "localhost"
port = 27080

co = bge.logic.getCurrentController()

game = co.actuators['Game']
net = co.owner

if(net['init']==1):
    try:
        net['clientTCP'] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        net['clientUDP'] = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        
        net['clientTCP'].connect((server,port))
        try:
            beat = pickle.load(net['clientTCP'].recv(1))
            id = pickle.load(net['clientTCP'].recv(1))
        except:
            beat = -1
            id = -1
        if(beat==-1 and id==-1):
            net['error'] = 1
            print("Unable to pickle.")
        
        net['clientUDP'].bind(("",port+1))
        net['clientUDP'].setblocking(0)

        net['init'] = 0
        print("Connected. Sending data.")
    except:
        print("Connection to server could not be made.")
        net['error'] = 1
        net['init'] = 0
elif(net['error']==0):
    data = 1
    while data is not 0:
        try:
            data, addr = net['clientUDP'].recvfrom(256)
            try:
                pickle.load(data)
            except:
                print("Can't pickle: ",data)
        except:
            data = 0
        if(data is not 0): print(data)
else:
    print("Data not sent because server timed out or is offline.")
    co.activate(game)

Server

import socket

port = 27080
clients = []

print("Apollox Iteration 0000

")

try:
	server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	server.bind(("localhost", port))
	server.listen(1)
	print("Server started on port ",port)
except:
	print("Apollox could not initialize the server.")
	input("Press Enter to quit.")

while 1:
	(client, addr) = server.accept()
	print(addr[0],":",addr[1]," connected.")
	try:
		i = clients.index(addr)
	except:
		print(client)
		try:
			client.send("0")
		except:
			print("FUCKING HELL!",client)
		try:
			udpSock = socket(AF_INET,SOCK_DGRAM)
			udpSock.setblocking(0)
		except:
			print("Failed to create udpSock")
		try:
			clients.append([client,udpSock,addr])
		except:
			print("Cannot append. Invalid/Nonexistant data given.")
			client.close()
	print(clients)

The server runs via the Python console while the client code is run from inside Blender.
Currently it seems to be unable to send data back to the client (as in sending a handshake’ish thing).
http://dl.dropbox.com/u/4618760/damnNetworking.png
I’m not really using pickle for anything yet.

If anyone knows how to properly setup a network, please let me know.

I’ve been trying to study the templates and other documents but most of them are outdated or simply don’t work in the way I want my server and clients to work.

Kind regards.

Let me first show you some useful code.
Instead of just using try: except:
modify the exept statement after ‘client.send’ so that it now reads:
except Exception as error:

Exception is capitalised first letter.
Now, print(Exception) after the client.send.

Additionally, in the part of the server which creates a connection, you’ve typed:
udpSock = socket(AF_INET,SOCK_DGRAM)
should it not be:
udpSock = socket.socket(AF_INET,SOCK_DGRAM)

Agoose77 had some very valid points.

Additional to that:

Avoid long try…except blocks.
Otherwise

  • You will not know what was executed and what not.
  • You will not know what statement produced the error.

using “net[‘clientUDP’]”
all the time means each statement is a search in the dictionary. The python access is quite fast, but this is not necessary to do that.

Better:

  • assign it to a variable
  • use this variable

e.g.


clientUDP = ...
net['clientUDP'] = clientUDP 
net['clientUDP'].bind(..

The code structure means the client sends data only once.
This is because the sending is in the init block.
Finally the socket connection is not closed after usage.

I suggest to separate connection handling from sending:
e.g.
openConnection()
sendData()
closeConnection()

“is 0”
For not existing data use None rather than 0 (None exist for exactly this case ;))

port = 27080
Better read the connection parameters (host, port) from properties rather than force the user to change the code.

“While 1:”
I can’t see you ever exit from the loop. (And never create an endless loop in the BGE!)

I hope it helps


port = net.get('port', 27080)

Is a nice way to “just work” with a default port and still the user can change it by setting a property.

update: I assume the server code runs outside BGE - else it need to be in a thread. Never create a infinite loop in BGE unless in a thread.

The server is running outside of Blender yes.
The ‘port’ variable is just temporary.
I’m now also using the logging module on the server side but it’s messy.

I’ve fixed the client.send issue. I had to encode the data to bytes.
Still I can’t get my head around it.
Does anyone of you know a good example of networking in Blender 2.6?

And thanks for the help so far. :slight_smile:

agoose77 have a network component that might be wort looking at. I will look in to this some day myself, because I want P2P networking…

I would like it to be just a server and allow clients to connect to that and receive data from it. So no P2P in general.
I took a look at a link in agoose77’s signature but the tutorial on his website leads to a 404 page.

No, did not suggest You use it, and it not any day soon anyway - Just ranted about what I want. Don’t really know why :slight_smile:

Sorry about the link, ill fix it. -> here is the page.
http://hostilestudios.com/networking/tutorials/basic.php
Here is some easy UDP code.
You can expand this to make it dynamic, by having the server save the connecting client’s connection (called conn in the recvfrom part of the server) and send to that, as well as creating a new connection dedicated just for that client.


import bge
import socket
import pickle
def server(cont):
    own = cont.owner
    port = 1000
 
    def init():
        connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        connection.bind(('127.0.0.1', port))
        connection.setblocking(0)
        print('Server started')
        own['connection'] = connection
    if not 'connection' in own:
        init()
 
    connection = own['connection']
 
    try:
        data, conn = connection.recvfrom(1024)
        print(pickle.loads(data))
    except Exception as e:
        pass #no data received
 
def client(cont):
    own = cont.owner
    port = 1010
    server_ip = '127.0.0.1'
    server_port = 1000
 
    def init():
        host = (server_ip, port)
        connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        connection.bind(host)
        connection.setblocking(0)   
        print('Client Connected')
 
        own['host'] = host
        own['connection'] = connection
    if not 'connection' in own:
        init()
 
    host = (server_ip,server_port)
    connection = own['connection']    
 
    if bge.logic.keyboard.events[bge.events.SPACEKEY]==1:
        data = pickle.dumps(('Hello Mr Server'))    
        connection.sendto(data,host)