Idle socket causing delayed data transfer

I have a telnet type client written that has a thread to continually read data from the socket with the server. The problem is, that when the connection is idle for a significant amount of time (no data transfered), the connection enters "delay state" (that's what I'll call it). In this state, if data were to begin transferring again, nothing is read from the InputStream until a while later (minutes).

From my observations, I believe the delay time reduces if more data is queued up.

Here is my thread code:

publicvoid run(){

inputField.requestFocusInWindow();

if(!init())return;

byte[] buff=newbyte[buf_size];

int nch;

thread:while(this==Thread.currentThread()){

try{

if ((nch = in.read(buff, 0, buff.length)) == -1){

addMessage("Natural disconnection from host.");

disconnect();

break thread;

}

outputArea.append(buff,nch);

}catch(Exception e){

if(einstanceof IOException)

addMessage("Forcibly disconnected from host.");

elseif(einstanceof DataFormatException)

addMessage("Fatal error - data corrupted. Disconnecting.");

else//else I don't know what happened, so print the raw data

addMessage(e.toString());

disconnect();

break thread;

}

}

}

You'll notice a lot of references to my own methods. I think their naming is fairly self explanatory, but if you need clarification, feel free to ask.

Message was edited by:

natmaster

[2561 byte] By [natmastera] at [2007-10-2 21:32:21]
# 1
Why is my formatting not working?
natmastera at 2007-7-14 0:45:51 > top of Java-index,Core,Core APIs...
# 2
I can't see anything wrong with your code but I am curious how this == Thread.currentThread() is ever going to be false, and where you're going to get a DataFormatException from.Is the sender flushing?
ejpa at 2007-7-14 0:45:51 > top of Java-index,Core,Core APIs...
# 3

DataFormatException can happen because I might negotiate compression in my transfers. When the compression occurs, if the data is corrupted it'll throw this Exception. (Standard java libraries.)

The thread loop is pretty standard stuff - it just assures that the thread doesn't hog the computer (ie. only executes til the end of the loop, then checks if it needs to let other threads execute.) If you're confused about this, try checking about the Threads tutorial. http://java.sun.com/docs/books/tutorial/essential/threads/index.html

natmastera at 2007-7-14 0:45:51 > top of Java-index,Core,Core APIs...
# 4

With ejp's pedigree on this forum, i think he understands threads!

I think you've misinterpreted that tutorial. In the tutorial i found this code:

public void run() {

牋Thread myThread = Thread.currentThread();

牋while (clockThread == myThread) {

牋牋repaint();

牋牋try {

牋牋牋Thread.sleep(1000);

牋牋} catch (InterruptedException e) {

牋牋牋//The VM doesn't want us to sleep anymore,

牋牋牋//so get back to work.

牋牋}

牋}

}

which i presume you're referring to, but that only works because the code is run from an applet with a stop method that sets clockThread to null. It's nothing to do with fairness of executing threads.

Think about which thread is executing the statement "this == Thread.currentThread". Unless you're calling this run method from yet another unspecified thread, it's going to be "this", and if "this" is having a chance to execute any statements at all, then it's also going to be the current thread, so that statement will always be true.

If you want to be sure to be nice to other threads, you could call Thread.yield(). I never had much joy with using this method though, and the current JVMs seem to be pretty good at being fair to all threads even if none of them sleep or yield at all

[Sorry about formatting, damned forum seems to be shagged to tried to do it manually with html tags]

sorabaina at 2007-7-14 0:45:51 > top of Java-index,Core,Core APIs...
# 5

A delay like that sounds odd. The only thing I can think of is the process gets swapped out - even then several minutes would be pretty extreme (though I do get that occasionally with a web browser in Windows). Is that a possibility in your setup? Does either end of the connection feel memory starved?

sjasjaa at 2007-7-14 0:45:51 > top of Java-index,Core,Core APIs...
# 6

Wow I feel silly. The thread seems to give itself up during the read until it gets I/O. I remember reading somewhere that IOs stop the current thread that called them until they receive some data, and then send a wake signal.

However, I don't think this is the problem here. To test this I had changed the code to check if IO was available in the loop, and then if so read it. This way, the loop will continue running as long as that thread isn't locked down or something horrible happened. Then I added a counter and had some data printed every 10 thousandth call (this caused a message to appear approximately every second). I waited to see if it would lock down, and sure enough it did. However, the printouts were still occurring at their regular interval when this occurred - so I know the data somehow got clogged up before or in my socket.

Is it possible my router is holding packets hostage if the socket is idle for a while, and then after enough build-up, realizes it should release them? I'm trying to think of reasons why this could happen, and I can't test that case too readily since I only have one connection to the net. On the other hand, I tested the issue with other programs that *SHOULD* work and got the same results - so maybe this isn't the client end. I did test connecting to myself locally to see if it was a routing issue and the problem seemed to not come up then; however, the repeating the results isn't always straightforward.

natmastera at 2007-7-14 0:45:52 > top of Java-index,Core,Core APIs...
# 7
Get rid of the sleep, get rid of the available() call, just call read().
ejpa at 2007-7-14 0:45:52 > top of Java-index,Core,Core APIs...
# 8
Are you referring to sorabain's code? I don't have any sleep or availible in mine - just read.
natmastera at 2007-7-14 0:45:52 > top of Java-index,Core,Core APIs...
# 9

So what does this mean?:

> ' I had changed the code to check if IO was available in the loop'.

So you must have had an available() call, or a ready() call. And what did you do if it returned zero? I assumed that you would sleep rather than just spin, but if you're spinning don't do that either, it's even worse.

Get rid of all these shenanigans. Stop comparing threads to themselves, stop trying to second-guess the scheduler and TCP/IP. Just call read() like everybody else. It will block until something is available; other threads will execute; it will then read as much as possible.

Message was edited by:

ejp

ejpa at 2007-7-14 0:45:52 > top of Java-index,Core,Core APIs...
# 10

I said I had done that to check to make sure all that was happening properly. It didn't change anything so I changed it back. This doesn't solve my problem.

I NEVER THOUGHT MY PROBLEM HAD TO DO WITH THREADS. There's a reason I posted this under networking. Now if you could please give me some ideas with regards to my actual issue. Thanks.

natmastera at 2007-7-14 0:45:52 > top of Java-index,Core,Core APIs...
# 11
OK. Is the sender flushing? (asked that in reply #2, not answered.) How big are the writes at the sender? How often do they occur? Have you considered the effect of the Nagle algorithm? Is there a router in between?
ejpa at 2007-7-14 0:45:52 > top of Java-index,Core,Core APIs...
# 12

I'm pretty sure the sender is flushing. I'm not sure of the write size and frequency off hand, but I know it does some buffering. What effect do you mean?

Yes there is a router. I recently heard about sockets commonly blocking - it sounds like that could be the issue. Any ideas on that, and possibly how to handle it?

Thanks for your help so far.

natmastera at 2007-7-14 0:45:52 > top of Java-index,Core,Core APIs...
# 13

I've never heard of 'sockets commonly blocking'.

The Nagle algorithm delays sending small packets if there are already outstanding acknowledgements. See ftp://ftp.rfc-editor.org/in-notes/rfc896.txt. As it says in the RFC, normally this is a very good idea, as it allows packet coalescing to take place at the sender; but when you are sending very small packets, e.g. in a Telnet client, it is sometimes recommended to turn the algorithm off. In Java this is done via Socket.setTcpNoDelay(true);

ejpa at 2007-7-14 0:45:52 > top of Java-index,Core,Core APIs...
# 14
After much experimentation, I realized the problem exists no matter what client I use. I assume SOMEONE has written a client properly, so it must be the server - or the connection between me and the server. In this case, is there anyway I can detect this has occurred and alert the user?
natmastera at 2007-7-14 0:45:52 > top of Java-index,Core,Core APIs...