Java TCP stream termination - java

I am trying to read from a tcp stream a message sent from client.
Thing is after reading the last line, my readline function is not returning null and i am not able to debug why, as control point is lost.
In short, after last line read, readLine function should return null, but i am not getting any thing as such.
this is what my code looks like
StringBuffer sipBuffer = null;
String lineRead = null;
readIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
try {
sipBuffer = new StringBuffer();
while ((lineRead = readIn.readLine()) != null) {
sipBuffer.append(lineRead);
sipBuffer.append("\n");
}
} catch (Exception ex) {
sipConsole.addText("Error in message: \n");
sipConsole.addText(ex.getMessage());
return;
}
format of message is
String inviteReq = "INVITE sip:" + destIP + "#sip.umsy.edu SIP/2.0" + "\n"
+ "From: \"" + myName + "\" <sip:" + myIP + "#sip.umsy.edu>" + "\n"
+ "To: <sip:" + destIP + "#sip.umsy.edu>" + "\n"
+ "Allow: INVITE, ACK, BYE" + "\r\n";

Has the client closed the stream it is writing to? If it hasn't, your readLine() is blocking for more data from the client. Client-server protocols typically establish a mechanism (other than stream close) to indicate size. Whether it is a content-length or through a special token.

readLine() will return null when the stream is closed. Are you really sure the stream gets closed ?
It seems you're reading a SIP message in which case the other end probably won't close the connection until the call is complete- or atleast until it's either answered or terminated before it gets answered. You'll have to follow the SIP protocol, and handle messages on the stream according to the SIP spec.

Please check if you are flushing and closing the OutputStream on the client side to not have your InputStreamReader blocked and waiting forever on the server side?

Be sure to close the connection on the client side once the message is sent. Otherwise, the server side will block and wait for more data.

I suspect that the client did not close the socket after sending the message, so the server is blocked waiting for new lines. Is this the case?
Remember that readline() returns null only if the end of stream is reached.
If your protocol requires a constantly open connection between the client and the server, you will have to detect the end of message in a different way.

Related

Unsuccessful in trying to reuse Java client socket

I have a software driver which communicates with a third-party controller; I have an API for using the latter but no visibility of its source code, and the supplier is not co-operative in trying to improve things!
The situation is as follows.
To send a request to the controller, I send an XML packet as the content of an HTTP POST to a servlet, which then sends me the response. The original code, implemented by a previous developer, works stably using java.net.Socket. However, our driver is implemented such that a new socket is created for EVERY request sent and, if the driver gets busy, the third-party controller struggles to keep up in terms of socket handling. In fact, their support guy said to me: "You really need to leave 5 seconds between each request...". This simply isn't commercially acceptable.
To improve performance, I wanted to try leaving our end of the socket open and reusing the socket pretty much indefinitely (given that connections can drop unexpectedly of course, but that's the least of my concerns and is manageable). However, whatever I seem to do, the effect is that if I use Comms.getSocket(false), a new socket is created for each request and everything works OK but bottlenecks when busy. If I use Comms.getSocket(true), the following happens:
Controller is sent first request
Controller responds to first request
Controller is sent second request (maybe 5 seconds later)
Controller never responds to second request or anything after it
postRequest() keeps getting called: for the first 12 seconds, the console outputs "Input shut down ? false" but, after that, the code no longer reaches there and doesn't get past the bw.write() and bw.flush() calls.
The controller allows both HTTP 1.0 and 1.1 but their docs say zilch about keep-alive. I've tried both and the code below shows that I've added Keep-Alive headers as well but the controller, as server, I'm guessing is ignoring them -- I don't think I have any way of knowing, do I ? When in HTTP 1.0 mode, the controller certainly returns a "Connection: close" but doesn't do that in HTTP 1.1 mode.
The likelihood is then that the server side is insisting on a "one socket per request" approach.
However, I wondered if I might be doing anything wrong (or missing something) in the following code to achieve what I want:
private String postRequest() throws IOException {
String resp = null;
String logMsg;
StringBuilder sb = new StringBuilder();
StringBuilder sbWrite = new StringBuilder();
Comms comms = getComms();
Socket socket = comms.getSocket(true);
BufferedReader br = comms.getReader();
BufferedWriter bw = comms.getWriter();
if (null != socket) {
System.out.println("Socket closed ? " + socket.isClosed());
System.out.println("Socket bound ? " + socket.isBound());
System.out.println("Socket connected ? " + socket.isConnected());
// Write the request
sbWrite
.append("POST /servlet/receiverServlet HTTP/1.1\r\n")
.append("Host: 192.168.200.100\r\n")
.append("Connection: Keep-Alive\r\n")
.append("Keep-Alive: timeout=10\r\n")
.append("Content-Type: text/xml\r\n")
.append("Content-Length: " + requestString.length() + "\r\n\r\n")
.append(requestString);
System.out.println("Writing:\n" + sbWrite.toString());
bw.write(sbWrite.toString());
bw.flush();
// Read the response
System.out.println("Input shut down ? " + socket.isInputShutdown());
String line;
boolean flag = false;
while ((line = br.readLine()) != null) {
System.out.println("Line: <" + line + ">");
if (flag) sb.append(line);
if (line.isEmpty()) flag = true;
}
resp = sb.toString();
}
else {
System.out.println("Socket not available");
}
return resp; // Another method will parse the response
}
To ease testing, I provide the socket using an extra Comms helper class and a method called getSocket(boolean reuse) where I can choose to always create a new socket or reuse the one that Comms creates for me, as follows:
public Comms(String ip, int port) {
this.ip = ip;
this.port = port;
initSocket();
}
private void initSocket() {
try {
socket = new Socket(ip, port);
socket.setKeepAlive(true);
socket.setPerformancePreferences(1, 0, 0);
socket.setReuseAddress(true);
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
br = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
System.out.println("### CREATED NEW SOCKET");
}
catch (UnknownHostException uhe) {
System.out.println("### UNKNOWN HOST FOR SOCKET");
}
catch (IOException ioe) {
System.out.println("### SOCKET I/O EXCEPTION");
}
}
public BufferedReader getReader() { return br; }
public BufferedWriter getWriter() { return bw; }
public Socket getSocket(boolean reuse) {
if (! reuse) initSocket();
return socket;
}
Can anyone help ?
If we assume that keep-alive thing is working as expected, I think the line while ((line = br.readLine()) != null) is a faulty one, as this is kind of infinity loop.
readline() returns null when there is no more data to read, e.g. a EOF, or when server/client closes the connection, that will break-down your reusing socket solution, since an open stream will never cause a null to a readLine() call, but blocking.
You need to fix the alg about reading a response (why not using implemented http client?), checking content-length, and when read the amount of required data from body, go for next loop by keeping the socket alive.
After that setting flag to true, you have to know what kind of data should be read(considering mime/content-type), besides that, the length of data, so reading data using readLine() may not be a good practice here.
Also make sure server allow for persistence connection, by checking if it respects it by responsing the same connection:keep-alive header.

Java Socket not receiving body of http request

I'm trying to read a HTTP request using only Socket and BufferedReader classes in Java. The problem is that I can't reach the body part of the request. The Buffered reader is giving me only the request line and the headers. Here is part of the code:
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String comando = "";
while((msgDoSocket = bufferedReader.readLine()) != null){
//telaOutput.adicionaFim(msgDoSocket);
try {
comando += msgDoSocket + " ";
//System.out.println(comando);
if(msgDoSocket.isEmpty()){
processaInput(comando);
}
} catch (Exception ex) {
Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
Here is a WireShark capture showing that the POST body is being sent. My program is running on port 15000 and the data is just a string "teste12345". I'm using the app POSTMAN from google chrome to send the requests.
I'm having exactly the same problem described in this thread but the solutions proposed there didn't work. The request still getting up to the last header and no more. Thanks in advance.
Edit: Problem Solved!
Following suggestion proposed on the answer, I changed the reading to:
reader = new DataInputStream(socket.getInputStream());
String comando = "";
while( (dt = reader.readByte()) >= 0){
comando += dt;
//... do the rest of the stuff
}
Reading it as binary made it possible to reach the body part of the request.
I'm far from being a Java guru, but I bet that readLine only returns with results when it found a sequence of \r\n. since your body is not terminated with \r\n the method readLine never returns. try to manually add that character sequence to your body and see what happens, or alternatively, use the raw InputStreamReader to read the body as byte array.
never the less, you can't expect any http body to actually be a string. it can also be a binary sequence which knows nothing about \r\n.

Socket communicating between java and c# applications

I have two applications, one written in Java and the other in C#. I am trying to send a string from the Java app to C# app.
My java code for sending the string is as follows:
String response;
try {
DataOutputStream outToServer =
new DataOutputStream(outGoingSocket.getOutputStream());
BufferedReader inFromServer =
new BufferedReader(new InputStreamReader(outGoingSocket.getInputStream()));
outToServer.writeBytes(message + '\n');
outToServer.flush();
response = inFromServer.readLine();
System.out.println("Received: " + response);
} catch (Exception ex) {
System.err.println("Exception in incoming socket: " + ex.getMessage());
}
My C# code for receiving the data is as follows:
Byte[] bytes = new Byte[1000];
String data = null;
try {
Console.Write("Waiting for a connection... ");
TcpClient client = incomingSocket.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int i;
while (true) {
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) {
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received:", data);
processReceivedMessage(data);
ackSocket(stream, "OK");
}
}
} catch (Exception ex) {
Console.WriteLine("Exception: ", ex);
}
I have a problem with receiving the data in the C# application. When I send the string "Data" in the Java app, and try to print the data received by the C# application using Console.WriteLine("Received: {0}", data), the output is:
Received: D
Received: ata
If I use Console.WriteLine("Received: ", data), the output is:
Received:
Received:
I want my C# application to receive the full string that is sent by the Java application. I tried to increase the buffer byte array size to 1000 but it doesn't help. I don't have experience using sockets, can someone show me what I did wrong?
So, as you can see, the receiving end picks up a response in chunks that might be considerably smaller than the total message.
You shouldn't be seeking to change this behaviour... it's a fact of network programming. It's your job to glue them back together again.
"I want my c# application receive the full string"
So, how is your receiving app meant to know that it has received the full string? Did you send a length field to indicate how much data is coming? Perhaps you expect \n to indicate the end of message? A zero byte?
If your terminator is indeed a newline, you might want to consider passing your NetworkStream to a StreamReader and calling ReadLine on it. Now, the StreamReader will keep reading from the stream until it hits a newline, then hand you the line.

input.read() never returns -1

I am writing a proxy server in Java.
Initially, I do (simplified)
server = new ServerSocket(5568);
incoming = server.accept();
input = incoming.getInputStream();
...
outgoing = new Socket(host, 80);
output = outgoing.getOutputStream();
output.write(inputbuffer, 0, i);
where inputbuffer is some collection of bytes received so far (I read the incoming data up until the part where I know the host header, and then open a connection to the server and send what I have so far). So server is my welcome socket, input is the data coming to my proxy from the client, and output is the data to the serve from my proxy.
Next, I want the output from the server to be written to the client in parallel with the client still possibly writing stuff to the server. So I create a separate thread to read from the client:
final InputStream finalInput = input;
final OutputStream finalOutput = output;
Thread sendingStuff = new Thread(){
public void run(){
int c;
while ((c = finalInput.read()) != -1){
finalOutput.write((byte)c);
finalOutput.flush();
}
finalInput.close();
finalOutput.close();
}
}
sendingStuff.start();
Finally, I have a different section in the main thread to read from the server and write that to the client.
InputStream reverseInput = outgoing.getInputStream();
OutputStream reverseOutput = incoming.getOutputStream();
int c;
while ((c = reverseInput.read()) != -1){
reverseOutput.write((byte)c);
reverseOutput.flush();
}
reverseInput.close();
reverseOutput.close();
What happens is I get input, and send output, but the browser spins forever and the line in the thread that's reading from the client never gets a -1 signal.
A lot of the time I get errors that say things like "invalid header name" or "your browser sent a request that the server could not understand" and I think it has to do with this problem I'm having. One time I even got an IOException: Socket Closed on the line that reads from the client.
So why isn't the client sending an EOF? And is this the right way to go about doing this?
"I think it's because my HTTP request has Connection: keep-alive. How do I handle this?"
I think maybe you can just open your socket once for one connection.
Try to have flag like isNewConnection. set it to true at first and after the connection is initiated, set it to false.

Read Special Characters in Socket Server

I am creating Client/Server using Java Networking API. My client will send special unicode characters to Server before and after message. Before message it will send \uc001B and after message \uc00C. After message has been send successfully again client will send \r to server. Server can identify by receiving of this that the message sending is done. But my problem here is how can I check in the server whether the message from client has \r.
DataOutputStream outToServer = new DataOutputStream( clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
outToServer.writeBytes("\uc001B");
outToServer.flush();
outToServer.writeBytes(message.toString());
outToServer.writeBytes("\uc001C");
outToServer.flush();
outToServer.writeBytes("\r");
outToServer.flush();
And here is my server Code to read messages from the client
in = new BufferedReader(new InputStreamReader(m_clientSocket.getInputStream()));
out = new PrintWriter(new OutputStreamWriter( m_clientSocket.getOutputStream()));
String receivingMessage = "";
while (m_bRunThread) {
String clientCommand = in.readLine().toString();
receivingMessage += clientCommand;
System.out.println("Client Says :" + clientCommand);
if (in.equals("\r")) {
System.out.print("Message Receiving from Client Done : "+ m_clientID);
m_bRunThread = false;
}
}
Thanks
You are using readLine(). It removes the newline, whatever it was: it understands all of them. Ergo you cannot possibly tell what the newline character was. Also you cannot possibly care. Every line you read was terminated by a newline character. But you are on fairly dangerous ground using STX and ETX in association with a Reader. You seem to have a protocol definition problem: you are sending STX/ETX and also expecting newlines. Why?

Categories