Sending information using sockets

Hi,

I’m using blender as a client to connect to a threaded java server in my game and Im stuck trying to send my character coordinates to the server, I have created a class containing all of the commands but Im struggling to get this position command working. The code for it is attached below, the main error I am getting is “cannot conver ‘tuple’ object to str implicitly”.

Any help would be greatly appreciated!!

import socketimport bpy
import time
import sys
from clientThread import clientThread
from bge import logic
from math import pi
import threading
from bge import render
bge.render.showMouse(1)
from commands import Commands
isIDset = False






init = bge.logic.getCurrentController().owner["init"]


if init == False:


    bge.logic.getCurrentController().owner[ "init" ] = True
   
    bge.logic.s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
    bge.logic.host = socket.gethostname( ) 
    bge.logic.port = 12345
    bge.logic.s.connect( ( bge.logic.host, bge.logic.port ) )     
    print( "Client: Connected to " + str( ( bge.logic.host, bge.logic.port) ) ); # print() required vs Python 2.7's print
    
    commands = Commands()
    
    #mystring = "%%setid SIMR
"
    #bge.logic.s.send( bytes(mystring, 'utf-8'))
    
    if not isIDset:
        
        msg = Commands.SETID + ' SimR 
'
        print ('%d C: sending message: %s', ( int(time.time()*1000), msg ))
        bge.logic.s.sendall( bytes( msg, 'utf-8'))
        #-an "ACK" should be received
        msglen = len( Commands.ACK )
        msg = ''
        try:
            done = False
            while ( not done ):
                ch = s.recv( 1 )
                if ( ch == '
' ):
                    done = True
                else:
                    msg += ch


      
        except:
            pass
        print ('%d C: received message: %s', ( int(time.time()*1000), msg ))


        #-create thread for receiving messages from the server
#        more = True
#        thread = clientThread( 1, id, s)
#        thread.start()
    else:
        isIDset = True
    #mystring2 = "%%send SIMR TABUI Hello
"
    #bge.logic.s.send(bytes(mystring2, 'utf-8'))
    
    
    
    def __init__(thread, id, s):
        more = True
        thread = clientThread( 1, id, s)
        thread.start()
        #-loop while user inputs messages to send to server
        while( more and thread.isRunning() ):
            try:
                msg = raw_input( 'type a string (bye to quit): ' )
                print ('%d C: sending msg [%s]', (int(time.time()*1000), msg ))
                bge.logic.s.sendall( bytes( msg, 'utf-8'))
                if ( msg == 'bye' ):
                    more = False
            except KeyboardInterrupt:
                print ('keyboard interrupt!')
                thread.stopRunning()
                more = False
            except Exception as e:
                print ('%d C: error: %s ') % ( int(time.time()*1000), e ), sys.exc_info()[0]
                thread.stopRunning()
                s.close()
                exit()
#data = bge.logic.s.recv( 1024 ).decode( "utf-8" )
##
#print( "Server: " + data );
##
#bge.logic.getCurrentScene().objects['Name'].text = data
#
cont = bge.logic.getCurrentController()
own = cont.owner
# 
b = own.position.x
c = own.position.y
d = round(b)
f = round(c)
#
mystring3 = int("x: %d y: %d", d, f)
print('x: ', d, 'y: ', f)
##data = int( data )
##data += 1
##data = str( data )
##
#bge.logic.s.send( bytes( mystring3, 'utf-8' ) ) # bytes() needed for Python 3.3 as str() does not handle buffer objects.
#
#
msg2 = Commands.POSE + "x: %d y: %d", d, f
print ('%d C: se3nding message: %s', ( int(time.time()*1000), msg2 ))
bge.logic.s.send( bytes( msg2, 'utf-8'))
#-an "ACK" should be received

The code’s quite messy, so it’s hard to work out what’s needed and what’s not. I’ve deleted anything with comments, and re-factored the code to create a simple “network peer” class which stores the socket and identity of the peer.

I’ve then added an init function and an update function, both for use by a Python module controller.

Your code that sends the position was doing some bizarre things with int(), and then failed to format the message to include the x and y coordinates. I’m also not sure if you want to send these as integers, it won’t give very precise positions.


import socket
import time


from bge import logic, render
from commands import Commands




class NetworkPeer:


    def __init__(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.host = socket.gethostname()
        self.port = 12345
        
        self.socket.connect((self.host, self.port))
        self.set_id()
       
    def set_id(self):
        msg = Commands.SETID + ' SimR 
'
        print ('%d C: sending message: %s', ( int(time.time()*1000), msg ))#
        
        sock = self.socket
        sock.sendall(msg.encode('utf-8'))
 
        identity = ''
        
        try:
            while True:
                char = sock.recv( 1 )
                if char == '
':
                    break
 
                else:
                    identity += ch


        except:
            pass


        print ('%d C: received message: %s', ( int(time.time()*1000), identity ))

        
def init(cont):
    own = cont.owner
    
    logic.network = NetworkPeer()
    render.showMouse(1)


def update(cont):
    own = cont.owner
    x, y = own.worldPosition.xy
    
    message = Commands.POSE + "x: {} y: {}".format(int(x), int(y))
    
    print ('%d C: sending message: %s', ( int(time.time()*1000), message ))
    logic.network.socket.send(message.encode('utf-8'))

    

Hey thanks for that, I’ve tried to run that code as the client and there are no errors but it does not connect to the server at all??

Are you running it in module mode, both init (no true pulse) and update (true pulse).
Give it a read through to see what it’s doing. :slight_smile:

I’ve had a play around with it and I cant get rid of the error ‘Networkpeer’ has no attribute ‘send’, I’ve had a look online but I can’t find anything. It connects to the server now and sets the ID but the error comes in sending the position

Change logic.network.send to logic.network.socket.send

Now all I’m getting is that the module has no attribute ‘socket’

You need to trigger the init function, and preferably before the update, or you’ll see that error once in the console. Easiest solution is to enable the F icon on the init python controller.

It would help if you uploaded the server so then I can test that.

I’ve enabled that, and I get errors shown in the image below


The Server is in java, I can’t seem to attach the file so heres the code:

public Server( int port ) {

	super();
	
	setServerState( States.STARTUP );


	// initialize port for communicating to clients
	this.port = port;
    
	// set up to accept a socket connection on port. if port has
	// value 0, then the constructor uses a free port.
	try {
	    serverSocket = new ServerSocket( port );
	} 
	catch ( IOException iox ) {
	    System.err.println( "S: could not listen on port: " + port + " " + iox );
	    System.err.println( "S: aborting <<<<<<<<<<<<<<<<<<<" );
	    System.exit( 1 );
	}


	// output information on where server is listening
	System.out.println( "S: server socket created: " );
	System.out.println( "S: port = "+serverSocket.getLocalPort() );
	// System.out.println( "S: local host address = "+serverSocket.getInetAddress().getHostAddress() );
	// simplified code from:
	// http://stackoverflow.com/questions/9481865/how-to-get-ip-address-of-current-machine-using-java
	try {
	    boolean found = false;
	    InetAddress inetAddr = null;
	    // Iterate all NICs (network interface cards)...
	    for ( Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements() && !found; ) {
		NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
		// Iterate all IP addresses assigned to each card...
		for ( Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements() && !found; ) {
		    inetAddr = (InetAddress)inetAddrs.nextElement();
		    if ( ! inetAddr.isLoopbackAddress() ) {
			// Found non-loopback site-local address. Return it immediately...
			found = true;
			System.out.println( "S: host name = " + inetAddr.getHostName() );
			System.out.println( "S: host address = " + inetAddr.getHostAddress() );
			break;
		    }
		}
	    }
	}
	catch ( Exception e ) {
	    System.out.println( "S: exception: " + e.toString() );
	}
    
	// create the Cleanup thread
	julio = new ServerCleanup( this );
    
	// ready, set, go!
	setServerState( States.LISTENING );
	this.start();


    } // end of Server constructor




    /**
     * main()
     *
     * Server is executed as a Java application, and this is the main
     * program for that application.
     *
     * The command line takes one option argument, the port number
     * which the Server will use to communicate with its clients.  If
     * a port number is not provided, then the Server uses the next
     * available port number, as provided by the system.
     *
     */
    public static void main( String[] args ) throws IOException {


	int port;


	// Extract a port number from the command line argument if one
	// exists.
	try{
	    port = Integer.parseInt( args[0] );
	}
	// If no port number provided, use a value of 0. This forces
	// the Socket constructor to find a free port by its own
	// devious methods.
	catch( ArrayIndexOutOfBoundsException aioobe ) {
	    System.out.println( "S: no port provided, so finding next available" );
	    port = 0;
	}
	Server server = new Server( port );


    } // end of main()




    /**
     * run()
     *
     * This method loops continuously, waiting for ServerThreads and
     * then creating objects to deal with them.
     * 
     * @exception IOException: if an input or output exception occurred
     *
     */
    public void run() {
	// listen for new clients
	System.out.println( "S: listening..." );
	try {
	    while ( getServerState() == States.LISTENING ) {
		// wait until a new client comes to town
		clients.add( new ServerThread( this, serverSocket.accept() ));
	    }
	}
	catch ( IOException iox ) {
	    System.err.println( "S: " + String.valueOf( iox ));
	}
	catch ( Exception x ) {
	    System.err.println( "S: " + String.valueOf( x ));
	}
	close();
    } // end of run()




    /**
     * setServerState()
     *
     * This method sets the Server's state.
     *
     */
    public void setServerState( int serverState ) {
	this.serverState = serverState;
    } // end of setServerState()




    /**
     * getServerState()
     *
     * Returns the Server's state.
     *
     * @return Server's state
     */
    public int getServerState() {
	return( this.serverState );
    } // end of getServerState()


    
    /**
     * getID()
     *
     * Obtain a new id for a new client provided we can count high enough. We don't
     * currently use this, rather we let each client suggest its own ID.
     *
     * To use it, make id a data element of the class.
     */
    public int getID(){
	int id = 1;


	if(id < Integer.MAX_VALUE){
	    return id++;
	}
	else{
	    return 0;
	}
    }


    /**
     * close()
     *
     * This method closes down the Server thread and exits the
     * application. This method will be called by a client that receives
     * a SHUTDOWN command. Otherwise this method would never be called,
     * since the thread blocks in serverSocket.accept(). So the call in
     * this method to serverSocket.close() may be ineffective and the
     * serverSocket = null may be the only thing that works.
     *
     */
    public final void close() {
	ServerThread c;
	int          i;
	// close...
	setServerState( States.SHUTDOWN );
	System.out.println( "S: stopping cleanup" );
	julio.stopThread();
	System.out.println( "S: killing server socket" );
	// we should do something clean like this first in order
	// to get the attention of the thread, which is 
	// blocking in serverSocket.accept() :
	// but this doesn't work so we have to force it by
	// just setting it to null
	serverSocket = null;
	System.out.println( "S: closing " + clients.size() + " clients" );
	for ( i=0; i<clients.size(); i++ ) {
	    c = (ServerThread)clients.get( i );
	    if ( c != null ) {
		c.close( true );
	    }
	}
	System.out.println( "S: exiting >>>>>>>>>>>>>>>>>>>" );
	System.exit( 0 );
    } // end of close()




    /**
     * find()
     *
     * This method returns a ServerThread pointer to the client in the
     * argument clients vector which matches this ID; returns null if ID
     * is not found.
     *
     */
    public ServerThread find( Vector them, String ID ) {
	ServerThread c;
	for ( int i=0; i<them.size(); i++ ) {
	    c = (ServerThread)them.get( i );
	    if ( c.ID == null ) {
		return( null );
	    }
	    else if ( c.ID.equals( ID )) {
		return( c );
	    }
	}
	return( null );
    } // end of find()




    /**                                                                                 
     * who()
     *
     * This method returns a string of ID's of all clients and their
     * current state.
     *
     * Note that we always check that client has an ID. This is done
     * because it can happen that one client invokes this routine
     * while another client is in the process of starting up and has
     * not read its ID yet.
     *                                                                                  
     */
    public String who( Vector them ) {
	String w = new String( "" );
	ServerThread client;
	if ( them == null ) {
	    w += "(none)";
	}
	else {
	    for ( int i=0; i<them.size(); i++ ) {
		client = (ServerThread)them.get( i );
		if ( client.getID() != null ) {
		    w += client.getID() + " (" + States.toString( client.getThreadState() ) + ") ";
		}
	    }
	    w += " |";
	}
	return( w );
    } // end of who()


} // end of Server class

I’m not sure what code you’re running for client2. It doesn’t look like the code I posted.

It is, its exactly the same, just doesnt have the time on the sent and recieved messages and Ive added the heading of the character

Can you upload the blend file?

Final screenshots with time.blend (624 KB)

Apologies it’s quite messy at the minute

Okay so it seems to be working, did you run it with the server? the pose message doesn’t appear to be getting to/displayed on the server?

It’s probably your server then
Final screenshots with time.blend (647 KB)

Unfortunately it needs to connect to the java server I posted before because the idea is that eventually the game is controlled by an android tablet that also connects to said tablet

You can still use a java server, it just needs to work! :wink:

Haha tell me about it!! Can the server you sent me be opened in a separate command window so I can see both sent and recieved messages?

Yes, it can:)

Okay so ive been trying to sort this for the last couple of days but no cigar just yet, the command window in blender is saying that it is sending the correct %%pose message yet this message is not being received by the server, I think that this could be somethong to do with the fact that when i print the values of logic.network.socket in the init and update functions they return a differet value (shown in screenshot below)

i have attached the latest version of the file also if you fancied taking a look for me??

Im greatly appreciative of your help by the way!!!


Final screenshots with time.blend (1.04 MB)