Java client/server multiplayer game socket We have a java client frozen

We have a java client/server multiplayer game system where at seemingly random times a message or messages that are being sent by the server to a client are not being received by the client. Once this happens then any subsequent messages sent by the server are not being received by the client. TCP/IP Server and Client sockets are being used. We are compiling using JDK1.4. The data we have collected strongly suggests that the server is properly outputting every message.

To summarize the problem and what we know:

1) All cases (5 or more) show that at some point the server sends a message that the client's read(...) method doesn't acknowledge;

2) Once this occurs, subsequent messages sent from the server face the same fate;

3) These messages vary;

4) In some cases the problem appears within minutes, in other cases it takes hours to appear;

5) In all but one case the server continues to receive and process messages from the client once the problem is encountered;

6) Use of the sniffer program shows that the packets for the unread server messages are being sent out over the internet and are in fact being received by the client;

7) After a certain delay in not reading any messages from the server, the client queries the server with a "hello" message that the server replies to with a "roger" message that the client's read(...) method doesn't acknowledge. This leads to the client disconnecting and calling the isInputShutdown() method that surprisingly returns false indicating that the client's input stream is still operational.

I have included below a description of some of the line numbers, class files and methods that are involved in the process below to give you some idea of how things are structured.

Server is running latest version of Linux OS and problems seem to usually happen with Windows OS clients

1) ClientConnection.java lines 236 - 262

synchronized public void write(String s) {

String ss = s + CR;

byte buf[];

if(status>0 && session.historyDebugFile>1) {

try {

session.fout.write("Output to "+name+" in seat "+tablePosition+": "+(s+CRLF).trim()+"\n");

} catch(IOException e) {

System.out.println("Write error on file " + session.historyFileName);

session.historyDebugFile = 0;

}

}

if (debug) System.out.println("SEND >>>> ["+fmt.format(new Date(System.currentTimeMillis()))+"] "+this.name+"["+this.clientId+"] : "+ s);

buf = ss.getBytes();

try {

out.write(buf, 0, buf.length);

out.flush();

}

catch (Exception e) {

System.out.println(sout = "Output Exception for clientId=" + clientId + " " + e);

server.serverHistoryFileProcessing(sout);

closing();

} finally {

System.out.println("out.write attempt complete");

}

}//~synchronized public void write(String...

2) ServerConnection.java lines 163 - 226

private String inputLine="", currentRead="";

private String readline() {

int i;

byte b[] = new byte[2000];

try {

System.out.println(" Time=["+fmt.format(new Date(System.currentTimeMillis()))+"] : Previous statement="+inputLine);

inputLine = "";

// iterate until complete message read

for(;;) {

// branch to attempt to read input stream

if(currentRead.equals("")) {

// branch if empty read

if((i=in.read(b, 0, 2000))<0) {

System.out.println("Problem - end of file encountered");

inputLine = "continue";

break;

}

currentRead = new String(b, 0, i);

}

// branch if end-of-message found

if((i=currentRead.indexOf(CR))>0) {

inputLine += currentRead.substring(0, i);

// branch if string contains (part of) next message

if(i<currentRead.length())currentRead=currentRead.substring(i+1);

else currentRead="";

timeout = false;

break;

}

System.out.println("End-of-message not found: currentRead="+currentRead);

inputLine += currentRead;

currentRead = "";

}//~for(;;) {

if(debug)System.out.println("input message: "+inputLine);

return inputLine;

}

catch(InterruptedIOException ie) {

int j = 0;

if(currentTimeoutIndex>=0)j=timeoutTimes[currentTimeoutIndex];

System.out.println("InterruptedIOException: " + ie);

System.out.println("isInputShutdown="+server.isInputShutdown()+" currentTimeoutIndex="

+currentTimeoutIndex+" time period="+j+" timeout="+timeout);

// branch to end processing due to disconnect

if(timeout)return "disconnect";

timeout = true;

send("hello"); // request response to avoid disconnect

setTimeout(5);

return "continue";

}

catch(IOException e) {

System.out.println("IOException: " + e);

System.out.println("isInputShutdown="+server.isInputShutdown()+" isOutputShutdown="

+server.isOutputShutdown());

return "disconnect"; // prepare to end processing

}

}//~private String readline(...

3) ServerConnection.java lines 312 - 327

public void run () {

String s, str[];

StringTokenizer st;

int i, j, k, count;

while ((s=readline()) != null) {

if (s.length() <=0)

{

if(debug)System.out.println("RECVED BLANK MESSAGE");

continue;

}

if(debug)System.out.println("<<<< RECVD ["+fmt.format(new Date(System.currentTimeMillis()))+"] : "+s);

st = new StringTokenizer (s);

-

Any thoughts, suggestions, and guidance will be very, very much appreciated.

Thanks

[5723 byte] By [highlander100a] at [2007-10-3 9:22:46]
# 1

Can you repost the code with formatting please? Nobody can read it in that form.

The first suspect has to be the client-side reading code (which you don't seem to have posted): perhaps you could just post that. Is the client getting a read timeout?

Your expectation that isInputShutdown() will tell you anything about the state of the connection is misplaced. All it tells you is whether this Java program has ever called shutdownInput() on this socket. Similarly for isConnected(), isOutputShutdown().

ejpa at 2007-7-15 4:36:28 > top of Java-index,Archived Forums,Socket Programming...
# 2

Sorry -- here are the relevant formatted sections of the code:

Server side write to socket:

synchronized public void write(String s) {

String ss = s + CR;

byte buf[];

if(status>0 && session.historyDebugFile>1) {

try {

session.fout.write("Output to "+name+" in seat "+tablePosition+": "+(s+CRLF).trim()+"\n");

} catch(IOException e) {

System.out.println("Write error on file " + session.historyFileName);

session.historyDebugFile = 0;

}

}

if (debug) System.out.println("SEND >>>> ["+fmt.format(new Date(System.currentTimeMillis()))+"] "+this.name+"["+this.clientId+"] : "+ s);

buf = ss.getBytes();

try {

out.write(buf, 0, buf.length);

out.flush();

}

catch (Exception e) {

System.out.println(sout = "Output Exception for clientId=" + clientId + " " + e);

server.serverHistoryFileProcessing(sout);

closing();

} finally {

System.out.println("out.write attempt complete");

}

}//~synchronized public void write(String...

####################################################

Client side read from socket :

....

private String inputLine="", currentRead="";

private String readline() {

int i;

byte b[] = new byte[2000];

try {

System.out.println(" Time=["+fmt.format(new Date(System.currentTimeMillis()))+"] : Previous statement="+inputLine);

inputLine = "";

// iterate until complete message read

for(;;) {

// branch to attempt to read input stream

if(currentRead.equals("")) {

// branch if empty read

if((i=in.read(b, 0, 2000))<0) {

System.out.println("Problem - end of file encountered");

inputLine = "continue";

break;

}

currentRead = new String(b, 0, i);

}

// branch if end-of-message found

if((i=currentRead.indexOf(CR))>0) {

inputLine += currentRead.substring(0, i);

// branch if string contains (part of) next message

if(i<currentRead.length())currentRead=currentRead.substring(i+1);

else currentRead="";

timeout = false;

break;

}

System.out.println("End-of-message not found: currentRead="+currentRead);

inputLine += currentRead;

currentRead = "";

}//~for(;;) {

if(debug)System.out.println("input message: "+inputLine);

return inputLine;

}

catch(InterruptedIOException ie) {

int j = 0;

if(currentTimeoutIndex>=0)j=timeoutTimes[currentTimeoutIndex];

System.out.println("InterruptedIOException: " + ie);

System.out.println("isInputShutdown="+server.isInputShutdown()+" currentTimeoutIndex="

+currentTimeoutIndex+" time period="+j+" timeout="+timeout);

// branch to end processing due to disconnect

if(timeout)return "disconnect";

timeout = true;

send("hello"); // request response to avoid disconnect

setTimeout(5);

return "continue";

}

catch(IOException e) {

System.out.println("IOException: " + e);

System.out.println("isInputShutdown="+server.isInputShutdown()+" isOutputShutdown="

+server.isOutputShutdown());

return "disconnect"; // prepare to end processing

}

}//~private String readline(...

....

public void run () {

String s, str[];

StringTokenizer st;

int i, j, k, count;

while ((s=readline()) != null) {

if (s.length() <=0)

{

if(debug)System.out.println("RECVED BLANK MESSAGE");

continue;

}

if(debug)System.out.println("<<<< RECVD ["+fmt.format(new Date(System.currentTimeMillis()))+"] : "+s);

st = new StringTokenizer (s);

highlander100a at 2007-7-15 4:36:28 > top of Java-index,Archived Forums,Socket Programming...
# 3

Well I'm not going to debug that reading logic but it is far too complicated for my taste and it wouldn't surprise me if it had a failure mode or two. I would just use the dreaded DataInputStream.readLine() if there are line terminators. And a timeout of 5 ms, or even 5s, is too short IMO, it should be more like 30 or 60 seconds. Don't use timeouts as a polling technique, use them as a failsafe.

ejpa at 2007-7-15 4:36:28 > top of Java-index,Archived Forums,Socket Programming...