Exception is thrown when trying to .stop() the server…

hello,



I think I have found a bug. In my program I create an instance of me.codeninja.spidermonkey.connection.Server. I create a me.codeninja.spidermonkey.connection.Client in my second program and let the Client connect to the Server. This works fine. When the Client is being disconnected from the Server, the Server would notice and it would dispatch an event to the ConnectionListener I have attached. Everything’s fine until here. Now, if I try to close the Server by Server.stop();, an exception is thrown to me.


12.10.2010 13:21:20 me.codeninja.spidermonkey.connection.Server stop
INFO: [Server#1][???] Server is shutting down..
java.nio.channels.ClosedChannelException
at sun.nio.ch.SocketChannelImpl.ensureWriteOpen(SocketChannelImpl.java:126)
at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:324)
at me.codeninja.spidermonkey.connection.TCPConnection.send(TCPConnection.java:213)
at me.codeninja.spidermonkey.connection.TCPConnection.sendObject(TCPConnection.java:177)
at me.codeninja.spidermonkey.connection.Server.broadcastTCP(Server.java:215)
at me.codeninja.spidermonkey.connection.Server.stop(Server.java:288)
at fl.onlinegame.server.conn.CONNHandler.destroy(CONNHandler.java:70)
at fl.onlinegame.server.general.command.CommandHandler.dispose(CommandHandler.java:53)
at fl.onlinegame.server.general.startandexit.ExitManager.exit(ExitManager.java:40)
at fl.onlinegame.server.exchange.command.sub.XExitCommand$1.run(XExitCommand.java:37)
at java.lang.Thread.run(Thread.java:619)


I believe the following error occurs: When Server.stop(); is called, the server tries to tell all its clients that it is intending to shut down now and therefore sends a DisconnectMessage to all of them. (see: Server.java:288) The problem comes up when the client which connected and disconnected earlier is still regarded as connected by the server-program. I believe the Client-connection was not properly removed from ArrayList Connection.connections (to be more precisely from Server.tcp.connections).

By using the debug function of eclipse, I have found out that when the client disconnects from the server, the ArrayList Server.clientManager.clients is empty while the ArrayList Server.tcp.connections still has one entry. When closing, the server tries to send his DisconnectMessage via Server.broadcastTCP. In TCPConnection.java:177 a for-block leaves through the ArrayList Connection.connections. Although, my client has disconnected, it would find an instance of Client in this ArrayList. The fact, that the Client's channel has already been closed in Connection.java:236 will actually throw the exception. I do not know why the TCPConnection's ArrayList connections would still hold this item. All I know is that when I debug my program and look at what happens in Connection.java:239, the instance of Client, whose Channel was just closed and is now to be removed, is not the same as the one which is in the ArrayList (which is obviously the reason why it's not removed). So for some reason the ArrayList in Connection holds the wrong instance of Client.

I hope you understand what I meant to tell you. I'm sorry, I couldn't work into further detail as I'm not fully understanding every part of SpiderMonkey, yet. I'm not even sure, whether this is a bug in my program or in SpiderMonkey.

Thanks in advance,
Fellkneul

I get the same exception when I use stop() and the client is allready disconnected.

Fellkneul covered the rest. :slight_smile:

Then it seems like it is really a bug in SpiderMonkey rather than one in my own code. I hope you will be able to fix this, Levia.

Moreover, is it true, that protected Server.clients is not used at all? Don’t you want to delete it? It’s not of such importance, but it would save another bit of memory, wouldn’t it? :wink:

I will look in to both issues posted (redundant code in Server, and stop() exception). Thanks for the report, sorry for the wait.

1 Like

No problem, man. Take your time. We are all very happy that you even created such a strong networking library. Tell us when you fixed it. Good luck.



gz,

Fellkneul

I fixed this problem, it was indeed an error that sneaked in when I started using ClientManager to manage client registrations. This is the test case I used:



[java]

import com.jme3.network.connection.Client;

import com.jme3.network.connection.Server;

import com.jme3.network.events.MessageListener;

import com.jme3.network.message.Message;



public class Test implements MessageListener {

public static void main(String[] args) {

try {

new Test();

} catch (Exception e) {

e.printStackTrace();

}

}



public Test() throws Exception {

Server server = new Server(4040, 5050);

server.start();



Client client = new Client(“localhost”, 4040, 5050);

client.start();



Thread.sleep(1000);



client.disconnect();



Thread.sleep(1000);

server.stop();



}



public void messageReceived(Message message) {

}



public void messageSent(Message message) {

}



public void objectReceived(Object object) {

}



public void objectSent(Object object) {

}

}

[/java]

It would indeed throw the exception you posted. Some explanation on the issue fixed:



Clients are combined into one to make sure you can send to both TCP and UDP, even though they are both different Connection classes. The TCPConnection (and UDPConnection) both still keep a registry of their own clients. As a result, I tried to disconnect the combined client in TCP/UDPConnection, while it should be their local (‘own’) client. I fixed this by doing a lookup on the appropriate client, and disconnecting that. The test case works perfectly for me now. (Redundant code in Server was removed as well, it was indeed an unused initialized ArrayList, thanks:))



I can’t stress this enough; Thank you so much for your continued support and bug reports, and please - keep them coming!



Edit: It’s in SVN now.

1 Like