Link to home
Start Free TrialLog in
Avatar of Mayank S
Mayank SFlag for India

asked on

Socket input-stream

Folks,

I'm facing a strange problem reading from the input-stream of a socket. If the socket on the other side is closed, inputStream.read () does not throw an IOException but simply waits, or sometimes reads a "?"

Anybody faced this before? Is this something new with Java 5? I'm running it on Windows 2003 Enterprise Server and the client for the server is also built in Java. I send bytes using outputStream.write () and later flush () it. On the server-side, I receive using inputStream.read (). If I deliberately close the client, the server thread either hangs, or sometimes reads some special character. The encoding used for data on both sides is the same (either UTF-8 or ASCII).

When I do a netstat, I can see that port shows me a TIME_WAIT. It should not be shown~! It should be disconnected.

Thanks,
Mayank.
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

>>or sometimes reads some special character.

That shouldn't be happening. Sounds like buffers are not getting flushed. As for the 'special character', it's sounding like an encoding problem. What data are you sending?

>>I can see that port shows me a TIME_WAIT. It should not be shown~! It should be disconnected.

Actually TIME_WAIT is normal, but i'm not sure why
Avatar of Mayank S

ASKER

Yeah the TIME_WAIT is normal as per http://support.microsoft.com/default.aspx?scid=kb;EN-US;q137984

Anyway, I tried with both encodings ASCII and UTF-8. While sending, I did outputStream.write ( dataString.getBytes ( encoding ) ) ; While receiving, I read the bytes into a ByteArrayOutputStream using inputStream.read (), then used byteArrayOutputStream.toString ( encoding ) to get the String contents. However, when the connection is broken from the other side, why is it not notified~!
>>I did outputStream.write ( dataString.getBytes ( encoding ) ) ;

Well i would begin by, as you yourself have said recently, by doing the following:

PrintWriter out = new PrintWriter(s.getOutputStream(), true);

>>why is it not notified~!

Not sure
>> Well i would begin by, as you yourself have said recently, by doing the following:

I knew this suggestion will come up but the problem is that the String will itself contain multiple new-lines (its an XML file), so I wanted to send them byte-by-byte, and receive at the other side byte-by-byte (not using bufferedReader.readLine () ) ;
>>will itself contain multiple new-lines (its an XML file)

Where are the new lines? If they're between nodes as opposed to node contents, then that's actually view-specific as opposed to model-specific and as such, not important

If the latter, just call print as opposed to println and flush regularly
>> If they're between nodes as opposed to node contents

They are between nodes. I will try with print () and let you know. I assume on the other side, it still remains as inputStream.read () ?
>>and flush regularly

(if not on auto-flush)


>>I assume on the other side, it still remains as inputStream.read () ?

Yes      
Same output. The server has got:

while ( true )
{
  ByteArrayOutputStream bs = new ByteArrayOutputStream () ;
  do
    bs.write ( is.read () ) ;
  while ( is.available () > 0 ) ;
  bs.flush () ;
  System.out.println ( bs.toString ( "ASCII" ) ) ;
}

is.read () returns everything correct initially. But then the loop runs again and waits at is.read (), then if the client disconnects, is.read () returns me a ? (some special character). It should throw an exception, right? I tried with all combinations like commenting/ uncommenting out.flush ()/ out.close () on the other side. If I use the platform-default encoding (simply bs.toString ()), I see that its just a blank space (rather nothing) being printed instead of the ?
BTW, sometimes this also returns a part of the data instead of the entire data. That shouldn't happen, right? That happens only on XP but not on Windows 2003.
That server code isn't right in several respects

a. bs is written to irrespective of the value returned by is.read
b. testing on available is unreliable
c. creating a BAOS in a potentially tight loop is dubious - just reuse the same one
d. if you're reading strings you would be better using Reader/Writer
I'm using strings but I don't have an end-character like new-line or something. So I don't want to use readLine (), etc because the data I'm reading might have multiple new-lines itself. That's why everything that is.read () returns is written into bs.

Creating the bs/ reusing is ok - I can do that but I don't think that will cause a functionality error.

However, you say that testing on available () is unreliable - then how else do I check if there is still some data in the input-stream? That is what the method is for, right?
Any ideas on what is the better approach to read 'as long as there is data in the stream' without using a length or an end-character kind of approach?
SOLUTION
Avatar of TimYates
TimYates
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Webstorm
Webstorm

also
  byte[] bfr = new byte[ 1024 ] ;
should be outside the while loop
Tim/ Webstorm - actually this was a .NET application where we had used NetworkStream.Read () and NetworkStream.DataAvailable. That worked fine in every run. While writing the same application in Java, the developers made some equivalent changes in the code (like changed it to read () and available ()). I will make these changes to read ( byte[], int, int) and see if it gets better.
>> which will not block

Yes it will...  It's a blocking IO call...

So the break isn't needed...

(as far as I know...  I may well be wrong with this) ;-)

Tim
I'm beginning to think that its a problem with my system. For some reason, the while loop above also works for some cases and just hangs in some cases.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Any other approaches you can suggest?

>> You simply read the stream to EOF

Meaning till -1?
Yes
Lesson learnt: don't use available () ;-)

I think we should make this change in the .NET version too - instead of using networkStream.DataAvailable, we should check for -1. It always worked in .NET for a year though :-O
:-)

Maybe - i do it exactly the same way in .NET
Didn't know that you were doing hands-on with .NET too. Thank God I am almost out of it ;)
Well i don't do much - i'm not into M$ ;-)
Good for us ;-)