Two way socket communication


#1

I’m trying to set up a simple socket connection between clients (eventually android/iphone users) and a server.The client connects, and the server checks to see if there are any messages for them in an sql database.

I am able to send information from the server to the client without any problems. My issue is sending information from the CLIENT to the server (for example, the server should first know the user’s id, so it can then query the database to determine if that particular user has any messages).

Any help on this would be greatly appreciated!

// file Server.hx

import sys.db.Mysql;

class Server {
    static function main() {
        var socket = new sys.net.Socket();
        socket.bind(new sys.net.Host("localhost"),5000);
        socket.listen(1); 									//listen for clients that are connecting to get information
        trace("Starting server...");
		//connect to server db: commented out for now so it will work on other machines
		//var databaseCnx = Mysql.connect({ host : "localhost", port : 3306, user : "root", pass : "", socket : null, database : "RPG" });
				
        while( true ) { //constantly running loop...
			var client : sys.net.Socket = socket.accept();
			//socket.setBlocking(false);
            trace("Client connected...");
				
			var input = socket.read();
			trace(input);
			//check for messages in database - commented out for now so it will work without the database connection...
/*
			client.write("checking for messages\n");
			var messageQuery = databaseCnx.request("SELECT * FROM message WHERE recipient = 1 AND status <3");
			//if there are messages try to contact the recipient
				for (row in messageQuery) {
					//trace(row.content);
					client.write("M"+"\t"+row.id+"\t"+row.sender+"\t"+row.recipient+"\t"+row.content + "\n");
*/
				}
			client.write("exit");
          //  client.close();
			//trace("Client disconnected...");
        }
    }
}
// file Client.hx
class Client {
    static function main() {
        var socket = new sys.net.Socket();
        socket.connect(new sys.net.Host("localhost"),5000);
        while( true ) {
			var l = socket.input.readLine();		
			//socket.write("hello world!");
			trace(l);
            if( l == "exit" ) {
                socket.close();
                break;
            }
        }
    }
}

in the terminal use ‘haxe client_server.hxml’ (see below) to compile. You can then open separate terminals to run ‘neko server.n’ and ‘neko client.n’ for testing.

# client_server.hxml
-neko client.n
-main Client.hx

--next
-neko server.n
-main Server.hx

#2

Does the client connect, or properly send any messages?


#3

Thanks for your response. Yes, the client connects to the server without issue.

When the SQL code is in place, the client connects to the server, the server runs a query, and then the server sends the results data to the client.

My problem is that I can’t send information the other way - from the client to the server. That is, I want to pass a variable ‘userID’ from the client to the server via the socket that has been opened between them, but I can’t find any way of doing this that works.

Edit: There was a line (hello world) that was one of my attempts to send a message from the cleint to the server that was breaking this verison - fixed now by commenting it out.


#4

Have you tried the openfl.net.Socket class?

I know multiple companies that have used this successfully. There is one minor patch that was made since the last release, that might be necessary, but perhaps that would work better (or at least serve as a reference):


#5

Thanks for the suggestion, I think I will transfer to using openfl - the socket implementation seems much more comprehensive!

That said, I’m having some trouble implementing this. I’ve been using notepad++ to create/edit my .hx files, and compiling them from the command line. When I add “import openfl.net.Socket;” to my server code, when I try to compile, I get the error “Type not found : openfl.net.Socket”.

I could switch to using haxeDevelop (I have been using this for prototyping my app) and use an openFL project, but would like to keep the server as a command line interface, and don’t know how I would do this using haxeDevelop.

Thanks again for your help here!


#6

Perhaps the server implementation could still use sys.net.Socket directly, while the client could use OpenFL and use openfl.net.Socket? What Haxe target do you use for your server? Neko?


#7

I wasn’t sure I’d be able to mix and match between the socket implementations, but can give it a try!

Yes I’m currently using neko for the server. I can get a client using openfl sockets to connect to the neko server, but then getting the client to read/write info was a problem (infinite busy loop without an error message when attempting to use the following:

while (true) {
if (socket.bytesAvailable > 0) {
var str = socket.readUFTBytes(socket.bytesAvailable);
//more code to parse the string etc.
}
}

I assume that socket.readUFTBytes() is the right thing to call (input is as shown in the server example above).


#8

Is it waiting for a NULL byte, or a length byte, or something else to know when the string is done, maybe?


#9

Thanks for the suggestion - I realized that the true loop was probably the cause of the problem, so I put the code inside an everyFrame event.

Here’s the ‘toy’ working code for the client…

package;

import openfl.display.Sprite;
import openfl.Lib;

import openfl.net.Socket;
import openfl.events.Event;

/**
 * ...
 * @author Bobby
 */
class Main extends Sprite 
{
	public var socket = new Socket();
	public function new() 
	{
		super();
			
		//setup socket...
			socket.connect("localhost", 5000);
			trace('Connected to server');	
			
		//add event to run on every frame
		this.addEventListener(Event.ENTER_FRAME, everyFrame);
	}

	private function everyFrame(event:Event):Void {
		if (socket.bytesAvailable > 0) {
			var str = socket.readUTFBytes(socket.bytesAvailable);
			trace(str);
			socket.writeUTFBytes("Message Recieved!");
		}
	}
	
}

Problem is that I’m kind of back to square one… The client can get information from the server with no problem, but the server can’t receive information from the client. Here’s the server code:

// file Server.hx
package;

import sys.db.Mysql;

class Server {
    static function main() {
        var socket = new sys.net.Socket();
        socket.bind(new sys.net.Host("localhost"),5000);
        socket.listen(1); 									//listen for clients that are connecting to get information
        trace("Starting server...");
		//connect to server db
		var databaseCnx = Mysql.connect({ host : "localhost", port : 3306, user : "root", pass : "", socket : null, database : "RPG" });
				
        while( true ) { //constantly running loop...
			var client : sys.net.Socket = socket.accept();
			//socket.setBlocking(false);
            trace("Client connected...");
			
			//check for messages in database...
			client.write("checking for messages\n");
			var messageQuery = databaseCnx.request("SELECT * FROM message WHERE (sender = 1 OR recipient = 1) AND status <3");
				for (row in messageQuery) {
					client.write("M"+"\t"+row.id+"\t"+row.sender+"\t"+row.recipient+"\t"+row.content+"\n");
				}
			
			try {
			var input = socket.input.readLine();
			trace(input);
			}	
			catch (err:Dynamic){ 
			trace("error attempting to get input");
			}	
				
				
				
			client.write("exit\n");
            client.close();
			trace("Client disconnected...");
        }
    }
}

The client receives the data from the server and tries to send a message back, but the server always throws an error when receiving the data. Any idea what I am missing here?


#10

There’s a little patch I linked to earlier on our development builds, I think in HTML5 our socket implementation was receiving a message then acting like it was disconnected, so it would reconnect constantly, which could interfere with some server behavior. I think the native behavior worked alright.

Should socket.accept () be in your while loop, or should you accept, then perform readLine () in a loop until the message is complete?


#11

Just to say a big thanks here - in the end I used the neko threadserver example and modified some code I found to get it running. At the client side I started using the openfl socket implementation and just managed to send some two-way messages. Thanks again!