Solved

Reading from a stream locks up

Posted on 2003-11-12
31
550 Views
Last Modified: 2013-11-18
I have a program that listens to a port from a server that sends XML messages.  I listen and get the XML through a URL connection and then read in the stream like this below.   The problem is it seems to hang up when it gets the last tag from the XML.  By hang up, I mean when I step through the code at gets at clientStream.read after a couple iterations, my debugger stays at "stepping" forever and the program never ends until I terminated it.   What can be the problem?  I was trying to see if I can get the length of the incoming stream so I can tell the loop to run until it reaches the end, but I don't know how to do that.  Does somebody know?  Thanks.  I've tried different ways of reading the stream like reading it line by line but I get same result.

BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));            
BufferedReader inData = new BufferedReader(in);
InputStream clientStream = client.getInputStream();

while ((readstream=clientStream.read()) >= 0)
{
if ( readstream == 13 ) continue;
reqData[i] = (char)readstream;
i++;
}
0
Comment
Question by:Mero
  • 11
  • 11
  • 5
  • +2
31 Comments
 
LVL 86

Expert Comment

by:CEHJ
ID: 9733019
>>so I can tell the loop to run until it reaches the end

Effectively you're doing that anway. And as it happens you're doing it in the most reliable way. Your code seems strange in some respects though. You should just get the stream once and read from it

while ((readstream=in.read()) >= 0)

Don't forget here:

>>if ( readstream == 13 ) continue;

that Windows also uses '\n' (ascii 10) for line feeds as part of its "\r\n" pair
0
 

Author Comment

by:Mero
ID: 9733113
thank for your reply,

going through it once doesn't get everything that is coming in.  In fact, part of the definition of the read() method in the JavaDoc is that it reads "some" bytes.
0
 
LVL 5

Expert Comment

by:lwinkenb
ID: 9733483
>>I was trying to see if I can get the length of the incoming stream so I can tell the loop to run until it reaches the end, but I don't know how to do that.

You cant programmatically get the size of the data stream in the buffer, but you could maybe send the size of the incomming stream before you send the data.

Another thing you can try, is ending your stream with a byte value of 0.  That way your receiving program knows when it has recieved everything.

while ((readstream=clientStream.read()) >= 0)
{
if( readstream == 0 ) break;
if ( readstream == 13 ) continue;
reqData[i] = (char)readstream;
i++;
}
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9733485
>>going through it once doesn't get everything that is coming in.

What you should be doing, if the messages are arriving at arbitrary intervals, is reading it in a loop:
StringBuffer buffer = new StringBuffer();
String line = null;
BufferedReader in = null;

....


while (receiveMessages) {
  buffer.setLength(0);
  in = new BufferedReader(new InputStreamReader(client.getInputStream()));  
  while ((line=in.readLine()) != null) {
    (buffer.append(line);
  }
  String message = buffer.toString();
  in.close();
}
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9733527
>>Another thing you can try, is ending your stream with a byte value of 0.

That's not really an extensible implementation - for instance, it could not be used for 'binary' data.

A better way to know when you've finished reading, and to ensure the correct operation of the underlying TCP/IP, whatever is sending messages should get the output stream, use it, and close it for each message.
0
 

Author Comment

by:Mero
ID: 9733865
cehj, I tried your example, but now it locks up on the first try.  lwinken, readstream never gets to 0 before it locks up.  The xml is sent through a third party program which I don't have control over.  

I want to add that this is what happens before I start reading the data:
ss = new ServerSocket(6050);
Socket client =ss.accept();
ClientThread t = new ClientThread(client);
t.run();

t.run is where I have the code that is trying to read the incoming stream.  I'm pretty much listening to port 6050 to get this xml.  Any other ideas?   Thanks for all your suggestions.
0
 
LVL 92

Expert Comment

by:objects
ID: 9734955
First thing you should do is get rid of the following lines, they are not used:

BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));          
BufferedReader inData = new BufferedReader(in);
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9734988
I mentioned that before:

>>You should just get the stream once and read from it

Can you post ClientThread's run method?
0
 
LVL 92

Expert Comment

by:objects
ID: 9735036
Does the server close the connection once the xml message is sent?
If not then you'll get the behaviour you are seeing and you'll need some way to determine the end of the xml message.
0
 
LVL 92

Expert Comment

by:objects
ID: 9735042
>>You should just get the stream once and read from it

Getting the stream multiple times is fine.
It's the creation of Reader's that is the problem.
0
 
LVL 92

Expert Comment

by:objects
ID: 9735238
I mean may cause a problem.

The problem is more likely that the server is keeping the connection open after the xml has been sent.
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9735331
True, hence my earlier comment:

>>whatever is sending messages should get the output stream, use it, and close it for each message.
     
0
 

Author Comment

by:Mero
ID: 9735398
clientThread's run is pretty much what I posted above where its doing the reading but I'm posting it below.

I think the server is keeping the connection open.  I've e-mailed the vendor's support desk to see if they can tell me how the XML is sent through the server side.  But I am open to any suggestions or anything I can try in the meantime since I don't think they'll get back with me soon.  Thanks.


public ClientThread()
{
super();
}
ClientThread(Socket client)
{
this.client = client;
}

public void run()
{
BufferedReader in =
new BufferedReader(new InputStreamReader(client.getInputStream()));

BufferedReader inData = new BufferedReader(in);
InputStream clientStream = client.getInputStream();

while ((readstream=clientStream.read()) >= 0)
{
if ( readstream == 13 ) continue;
reqData[i] = (char)readstream;
i++;
}
}
0
 
LVL 92

Expert Comment

by:objects
ID: 9735405
>whatever is sending messages should get the output stream, use it, and close it for each message.

What the server does is up to it, it is up to the client to use it appropriately.

You need to find out from the server if they provide any markers to indicate the end of the xml message.

Another thing to try would be to pass the stream directly to your XML parser and let it detect the end of the message.

0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 92

Expert Comment

by:objects
ID: 9735453
>  I'm pretty much listening to port 6050 to get this xml.

Why are you listening to 6050. This implies that the server is connecting to you.
Shouldn't you be connecting to the server.
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9735478
If you can't control what's happening at the server then just react to the end of the xml message instead of listening for EOF. This will presumably be the close of the root tag.
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9735502
In which case, replace

>>
 while ((line=in.readLine()) != null) {
    (buffer.append(line);
  }
>>

with

 while ((line=in.readLine()).indexOf(CLOSE_ROOT_TAG) < 0) {
    (buffer.append(line);
  }
0
 
LVL 92

Expert Comment

by:objects
ID: 9735595
> If you can't control what's happening at the server then just react to the end of
> the xml message instead of listening for EOF.

As I stated in my previous comment :D

> while ((line=in.readLine()).indexOf(CLOSE_ROOT_TAG) < 0) {

Not very safe
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9735649
>>Not very safe

There should be only one closing root tag, so I don't see why it isn't safe
0
 
LVL 92

Expert Comment

by:objects
ID: 9735714
a. There could be many.
b. Thats not the only reason it's unsafe

0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9735751
a. The code will loop for the next one
b. Please elaborate
0
 
LVL 92

Expert Comment

by:objects
ID: 9735790
a. i don't think so
b. there are many
0
 

Author Comment

by:Mero
ID: 9736153
objects is right.   The XML coming in could be any XML message.  I can't check for the closing tag.   The server is connecting to my machine where I am running my code and listening.
0
 
LVL 92

Expert Comment

by:objects
ID: 9736213
Have you tried passing the stream directly to an XML parser.

What exactly do you need to do with the XML once you have recieved it?
0
 

Author Comment

by:Mero
ID: 9736304
Nope, haven't tried an XML parser because I don't have the time to implement one.   As the program name, SocketSplitter, suggests,  the purpose of this program is to channel incoming messages from that given port to 2 other ports for other applications to use.
0
 
LVL 92

Expert Comment

by:objects
ID: 9736324
There are lots of parser implementations available, a SAX parser sounds like it would be suitable for your application.

What do the other apps expect? Could you simply pass the data recieved directly to the other ports without worrying where the end of message was?
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9738673
>>The XML coming in could be any XML message

It seems strange that your message 'packet' is not standardized. Are you getting them from several different sources?

Broadly speaking, there are two approaches you could take here, which we have discussed already:

a. You use the TCP/IP sockets and streams and close them. We have eliminated this presumably as you have no control over implementation of the sending source of these messages.
b. You use a protocol. One of the minimum requirements of this would be to agree on a message format. You could of course extends this protocol to include all sorts of functionality, but you should probably, as in any other xml-based protocol, have a dtd-based message format.

I can't think of any good way to design software to receive messages that doesn't follow one of the above.
0
 
LVL 2

Accepted Solution

by:
Lunchy earned 0 total points
ID: 10197237
PAQed, with points refunded (250)

Lunchy
Friendly Neighbourhood Community Support Admin
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 10197252
>>If you have not responded to the Experts concerning your question or given an updated status, your points will not be refunded.

>>PAQed, with points refunded (250

??


0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Styling your websites can become very complex. Here I'll show how SASS can help you better organize, maintain and reuse your CSS code.
The viewer will the learn the benefit of plain text editors and code an HTML5 based template for use in further tutorials.
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now