Link to home
Start Free TrialLog in
Avatar of Mero
Mero

asked on

Reading from a stream locks up

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++;
}
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

>>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
Avatar of Mero
Mero

ASKER

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.
>>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++;
}
>>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();
}
>>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.
Avatar of Mero

ASKER

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.
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);
I mentioned that before:

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

Can you post ClientThread's run method?
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.
>>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.
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.
True, hence my earlier comment:

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

ASKER

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++;
}
}
>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.

>  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.
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.
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);
  }
> 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
>>Not very safe

There should be only one closing root tag, so I don't see why it isn't safe
a. There could be many.
b. Thats not the only reason it's unsafe

a. The code will loop for the next one
b. Please elaborate
a. i don't think so
b. there are many
Avatar of Mero

ASKER

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.
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?
Avatar of Mero

ASKER

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.
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?
>>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.
ASKER CERTIFIED SOLUTION
Avatar of Lunchy
Lunchy
Flag of Canada 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
>>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

??