TestNetworkStress Example Possible Issue

So I have been playing around with the networking examples and I ran into something weird I cannot just figure out.



I altered the TestNetworkStress Issue to be the following. Only altered a few lines which I’ve marked in the code.



[java]





package mygame;



import com.jme3.network.connection.Client;

import com.jme3.network.connection.Server;

import com.jme3.network.events.ConnectionAdapter;

import java.io.IOException;

import java.util.logging.Level;

import java.util.logging.Logger;



public class TestNetworkStress extends ConnectionAdapter {



@Override

public void clientConnected(Client client) {



// Thread.sleep(100);

System.out.println(“CLIENT CONNECTED: “+client.getClientID());

// client.kick(“goodbye”); //commented out because I want to print a list of connected clients at the end







}



public static void main(String[] args) throws IOException, InterruptedException{

Logger.getLogger(””).getHandlers()[0].setLevel(Level.OFF);



Server server = new Server(5110, 5110);

server.start();

server.addConnectionListener(new TestNetworkStress());



//original code with me trying to see why I could not get proper ID’s

// for (int i = 0; i < 5; i++){

// Client client = new Client(“localhost”, 5110, 5110);

//

//

//

// client.start();

//

// // System.out.println(“Client id” + client.getClientID());

// // Thread.sleep(1000);

//

// }



//Setup 4 new clients and according to the Client class the ID’s should be 1 through 4

Client client = new Client(“localhost”, 5110, 5110);

client.start();



Client client2 = new Client(“localhost”, 5110, 5110);

client2.start();



Client client3 = new Client(“localhost”, 5110, 5110);

client3.start();



Client client4 = new Client(“localhost”, 5110, 5110);

client4.start();



Thread.sleep(5000); //allow time for all threads to finish.

System.out.println(server.getConnectors());

}

}

[/java]



So I setup the code to just make 4 clients and the client ID’s should just be 1-4 each but if you run the code you will see thats not the case. Looking at the Client class and placing a println in the constructor (to follow what is happening). Here is my edited Client constructor



[java]Client(boolean connector) {

super(ServiceManager.CLIENT);

clientID = ++clientIDCounter;

System.out.println("Client:Clientid: " +clientID); //only line I added to see ID

this.label = “Client#” + clientID;



isConnector = connector;

if (connector) {

isConnected = true;

} else {

if (tcp == null) tcp = new TCPConnection(label);

if (udp == null) udp = new UDPConnection(label);

}

}[/java]



With this I get the following output of



[java]Client:Clientid: 1

Client:Clientid: 2

Client:Clientid: 3

Client:Clientid: 4

Client:Clientid: 5

Client:Clientid: 6

Client:Clientid: 7

Client:Clientid: 8

Client:Clientid: 9

Client:Clientid: 10

CLIENT CONNECTED: 10

Client:Clientid: 11

Client:Clientid: 12

CLIENT CONNECTED: 12

Client:Clientid: 13

Client:Clientid: 14

CLIENT CONNECTED: 14

Client:Clientid: 15

Client:Clientid: 16

CLIENT CONNECTED: 16

[Client#10, Client#12, Client#14, Client#16][/java]



What is going on??? Is this a bug?

Client’s are created as follows:



Client for TCP (ID 0 or 1, can’t remember :wink: sorry)

Client for UDP (ID 1 or 2)

Combined client (ID 2 or 3)



So one ‘connection’ (on both UDP and TCP) can take up to 3 ID’s. The combined client is the one you should be using :slight_smile: You’ll be getting those via the getConnectors method and on events.

I am running into the possibility of race conditions with the API for networking. Maybe I’m doing it wrong but after countless tests I have put together the following demonstration.



[java]package mygame;



import com.jme3.network.connection.Client;

import com.jme3.network.connection.Server;

import com.jme3.network.events.ConnectionAdapter;

import com.jme3.network.events.MessageAdapter;

import com.jme3.network.message.Message;

import com.jme3.network.serializing.Serializable;

import com.jme3.network.serializing.Serializer;

import java.io.IOException;

import java.util.logging.Level;

import java.util.logging.Logger;



public class TestNetworkStress extends ConnectionAdapter

{

@Serializable

public static class PingMessage extends Message

{

}



@Serializable

public static class PongMessage extends Message

{

}



private static class PingResponder extends MessageAdapter

{

@Override

public void messageReceived(Message message)

{

try

{

if (message instanceof PingMessage)

{

System.out.println(“Received ping message!”);

System.out.println(“Sending pong message…”);

message.getClient().send(new PongMessage());

}

else if (message instanceof PongMessage)

{

System.out.println(“Received pong message!”);

}

}

catch (IOException ex)

{

ex.printStackTrace();

}

}

}



@Override

public void clientConnected(Client client)

{

try

{

System.out.println(“ClientConnected:CONNECTED Clients: " + server.getConnectors());

client.send(message);

}

catch (IOException ex)

{

Logger.getLogger(TestNetworkStress.class.getName()).log(Level.SEVERE, null, ex);

}











}

public static Server server;

public static Client client;

public static PingMessage message;



public static void main(String[] args) throws IOException, InterruptedException

{

Serializer.registerClass(PingMessage.class);

Serializer.registerClass(PongMessage.class);

Logger.getLogger(”").getHandlers()[0].setLevel(Level.OFF);



message = new PingMessage();



server = new Server(5110, 5110);

server.start();

server.addConnectionListener(new TestNetworkStress());





client = new Client(“localhost”, 5110, 5110);

client.start();



server.addMessageListener(new PingResponder(), PingMessage.class);

client.addMessageListener(new PingResponder(), PongMessage.class);



// Thread.sleep(100);



System.out.println("Main:CONNECTED Clients: " + server.getConnectors());

client.send(message);



}

}

[/java]



produces the following output



[java]Main:CONNECTED Clients: []

Received ping message!

Sending pong message…

ClientConnected:CONNECTED Clients: []

Received pong message![/java]



Now commenting the line



[java] Thread.sleep(100);[/java]



The output becomes

[java]

ClientConnected:CONNECTED Clients: []

Main:CONNECTED Clients: [Client#4]

Received ping message!

Sending pong message…

Received pong message!

[/java]



I have tried sleeping the thread in the Connected Message [java]public void clientConnected(Client client)[/java]

but still cannot get the server Connectors List to fill out. On connection of the client the server list would need to be updated because in that method a developer may want to do such things as prepare game conditions then send a message to that client.



Also I have not been able to get [java] public void clientDisconnected(Client client) {} [/java] to fire. I have tried kicking the client from the server, and just regular disconnecting.

The server list ‘should’ be updated, especially when clientConnected is called, especially for that reason you gave :slight_smile: It’s weird that initially it goes into clientConnected() without having updated the connector list. I’ll check these problems out, thanks

Sorry if I gave the wrong reason. Hopefully you are able to figure out what is going wrong. About the infinite loop on disconnect it just has to do with the server still acting on the connection of the client who already disconnected. So client closes without using your provided api the error occurs. you are missing a portion to cleanup the connections close the socket when this exception occurs.



Here is just a quick overview of the exceptions that need to be handled when dealing with sockets. Obviously how you implement it is up to you



[java] if (ex instanceof SocketException)

{

if (ex instanceof BindException)

{

Logger.getLogger(Server.class.getName()).log(Level.INFO, “Socket already in use. Try starting the server on another socket.”);

}

else if (ex instanceof ConnectException)

{

Logger.getLogger(Server.class.getName()).log(Level.INFO, “ConnectException.”);

}

else if (ex instanceof NoRouteToHostException)

{

Logger.getLogger(Server.class.getName()).log(Level.INFO, “NoRouteToHostException.”);

}

else if (ex instanceof PortUnreachableException)

{

Logger.getLogger(Server.class.getName()).log(Level.INFO, “PortUnreachableException.”);

}

else if(ex.getMessage().equalsIgnoreCase(“Connection reset”))

{

Logger.getLogger(Server.class.getName()).log(Level.INFO, “Connection reset: Client Closed Connection foricibly.”);

}

else

{

Logger.getLogger(Server.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);

}

}[/java]



I started writing my own personal client server code and just had a question for you if you dont mind.

For the serialization why did you go through all of that trouble of writing your own when if you implement the class Serializable that already comes with the java api. By doing that it allows the java networking api to send it as an object over a socket?



Thanks a bunch!