Server receiving packets after timeout TCP/IP - java

I am writing simple Server through TCP/IP for my android app.
I am facing a problem where server only receives messages after the timeout on the app.
My server side:
System.out.println("Connection accepted");
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
capitalizedSentence = "READY";
writeToUser(outToClient, "READY".getBytes());
String response = readFromUser(connectionSocket);
// Server hangs on readFromUser();
if(response.contains("IL"))
{
byte[] bytes = DatatypeConverter.parseHexBinary(foo);
writeToUser(outToClient, bytes);
}
App side:
if (ack.equals("READY")) {
ack = "";
dataOutputStream.writeBytes(command);
dataOutputStream.flush();
buf = new byte[556];
dataInputStream.read(buf);
// app hangs on read() and gets timeout
}
The problem is that, server receives command only after application gets read timeout.
My current scenario is this:
Connection accepted: Application receives "READY"
Application sends commands and tries to read response from server
Server is hanging on readFromUser() and only receives message after the app gets read timeout.
Any ideas what am I doing wrong ?
Update:
The code works if I use readLine, instead of read(buf) ( if I understand clearly server hangs on read(buf) and is in waiting mode as socket is not closed yet even though no more data is beeing sent. )
However such way I have to add "\n" after each command, and server is only emulator, app works with different device who does not understand "\n" at the end and will crash.
Is there any way I could make this work without using readLine() ?
Update 2
public void writeToUser(DataOutputStream outToClient, byte[] bytes) throws IOException
{
outToClient.write(bytes);
outToClient.flush();
String s = new String(bytes);
writeLog("Sent to client: " + s);
}
public String readFromUser(Socket socket) throws IOException, InterruptedException
{
writeLog("Reading...");
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String clientSentence = inFromClient.readLine();
writeLog("Received: " + clientSentence);
return clientSentence;
}
Above readFromUser() method works just as expected. But, this requires adding "\n" on each command sent from client app. And real device I have to communicate with does not understand "\n" and will treat the command as unrecognized... I am writing this server simply for testing purposes and I want it to be as close to real one as possible.
Previously I was just trying to get it done without "\n" on each command using inFromClient.read(cbuf); instead of readLine() and server always got hung on read, and received command only after socket was closed on client side. Even though I know that client sent the command and is waiting for response.
The question is how can I receive command without using readLine(); and "\n" on client side.

'how can I receive command without using readLine(); and "\n" on client side'. If you do not, or can not, want to use "\n" as a command terminator, then you must use another protocol to identify the start and end of the 'command' within the TCP octet/byte stream.
What protocol does your 'real device' server use to identify the start and end of commands? If it uses a byte-by-byte state-machine to identify a valid command then you are going to have to duplicate that in your test server.

You're reading lines but you aren't writing lines. So readLine() blocks until a line terminator arrives or the peer closes the connection.
Append a \n.

Why not you increase timeout from APPs side. Or you can write a thread that will hit server in some interval for some time and if no response then show time out. This problem is in Apps side.

Related

Java TCP Socket Programming: Client and Server communicate well on the same computer, but fail to send data to each other over LAN

I am trying to set up a program where the server can communicate with multiple clients. The program is written in Java. I got it all working on the same machine so I decided to try LAN. I converted the program to JAR files and I tried connecting my laptop to my PC (both are on the same network). The connection is successful but unfortunately only 1 message arrives to the server. As you can see in the code below, I send multiple messages (Meaning that i write multiple times) via DataOutputStream. One defines the datatype (in the following example 0 means that it's a String) and the other sends the actual message data. I also print the size of the packets in bytes and it always matches the size of the DataOutputStream instance.
DataOutputStream dOut = new DataOutputStream(clientSocket.getOutputStream());
String str = "Hello";
//Type
System.out.println("Type output size: 1");
dOut.writeByte(0);
//Message
System.out.println("Message output size: " + (str.getBytes(StandardCharsets.UTF_8).length + 2));
dOut.writeUTF(str);
System.out.println("Length of all: " + (dOut.size()));
dOut.flush();
So now when the data from the client is sent we need to handle it on the server, which the code below does. It retrieves the InputStream from the Socket called client and inserts it into the DataInputStream. This is were it gets weird on LAN as the stream only contains the first message.
InputStream stream = client.getInputStream();
DataInputStream dIn = new DataInputStream(stream);
while(dIn.available() > 0) {
byte type = dIn.readByte();
switch(type) {
case 0:
System.out.println(dIn.readUTF());
break;
case 1:
System.out.println(dIn.readInt());
break;
case 2:
System.out.println(dIn.readByte());
break;
default:
throw new IllegalStateException("Unexpected value: " + type);
}
}
If you run the Client in the IDE on lets say a laptop connected to the same network and then you run the Server on a PC connected to the same network it will work. However, not if the programs are in JARS.
The actual stacktrace is the following:
java.net.SocketException: Connection reset
at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:323)
at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:961)
at
java.base/java.io.DataInputStream.readInt(DataInputStream.java:393)
The stacktrace does not tell me anything, but it points at case 0: in the switch case. It can't read the String as the DataInputStream does not contain any data (I guess?).
I would also like to state that the Server is multithreaded! I have one thread that adds the sockets when they are accepted through ServerSocket.accept() and I use the second (main thread) to read the data sent from clients.
I have selected the code above as I believe that the issue lies within it, however I am new to Socket Programming and I know that some of you would like to see other parts of the code. I will add more relevant code when I am asked.
I do not know why it acts like this, does anyone know why?
What have i tried?
I have tried waiting for packets - but that has only resulted in the
Server looping forever. With waiting for packets I mean not going forward until the DataInputStream contains enough bytes.
I have disabled Nagels Algorithm through setTCPNoDelay(false).
Tried to send different datatypes, but that also failed
I tried changing the first packet to a String which resulted in the String showing up in the DataInputStream.
I have tried portforwarding the port used and I have tried disabling the firewall on both computers.
Update 1
I have been taking advice from the comments which has led a to a few discoveries:
Closing the DataOutputStream successfully sends all packets to the client.
It is also possible to build your own buffer and decode it in the server. However, it is still not possible to send any more messages after this.
It worked as a JAR because IntelliJ was being nice (Eclipse threw the same error when running in IDE)
Update 2:
I think this post is relevant. It states that SocketException is sent when a client closes it's socket "ungracefully". And because my Client closes (as it is not in a loop) and I don't close the socket properly - it will close "ungracefully" and the data will be lost. Hence the error.
The issue is now solved, and the solution is quite logical. My client does not operate in a loop, rather it sends the data and closes the program. That sounds fine, but I forgot to properly close the socket of the client.
The reason why the second 'packet' never arrived was due to me doing this tiny mistake. The packet was on it's way through the local network but the client socket improperly closed it's socket before the packet arrived to the server, which is why I got a SocketException error. See this.
I solved the issue by putting socket.close() ,where socket is the client's socket, after I had sent all the messages I wanted to send.

TCP java chat, client not listen

I have problem with my ClientListener, server send TCP package but Client do not display it.
Here is my code
https://github.com/Behoston/sieci/tree/master/src/tcp
(Server run new thread for each new client and this thread (to listen) and this thread run other to sending messages (it works - I can see messages in wireshark
Client run main thread where can input some text and second therad (not working properly) to listen messages from serever)
It's quite hard to answer your question if you only provide a link to your repository, some code snippets of the crucial classes or methods would be helpful.
If my understanding of the classes you provided is correct, this is the workflow you are trying to implement (correct me if I'm wrong):
Server gets started
Client connects
Server sends a welcome message (which is not getting displayed on clientside):
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
outToClient.writeBytes("Hello, your ID is: " + clientId + "; To send message please use 3 first chars to set target");
On the recieving side:
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
response = inFromServer.readLine();
As far as I see, you are waiting for a readLine() with your server sending a byteArray. Since readLine() waits for a line seperator (f.e. "\n"), your messages can't be processed.

How do I recognize EOF in Java Sockets?

I want to recognize end of data stream in Java Sockets. When I run the code below, it just stuck and keeps running (it stucks at value 10).
I also want the program to download binary files, but the last byte is always distinct, so I don't know how to stop the while (pragmatically).
String host = "example.com";
String path = "/";
Socket connection = new Socket(host, 80);
PrintWriter out = new PrintWriter(connection.getOutputStream());
out.write("GET "+ path +" HTTP/1.1\r\nHost: "+ host +"\r\n\r\n");
out.flush();
int dataBuffer;
while ((dataBuffer = connection.getInputStream().read()) != -1)
System.out.println(dataBuffer);
out.close();
Thanks for any hints.
Actually your code is not correct.
In HTTP 1.0 each connection is closed and as a result the client could detect when an input has ended.
In HTTP 1.1 with persistent connections, the underlying TCP connection remains open, so a client can detect when an input ends with 1 of the following 2 ways:
1) The HTTP Server puts a Content-Length header indicating the size of the response. This can be used by the client to understand when the reponse has been fully read.
2)The response is send in Chunked-Encoding meaning that it comes in chunks prefixed with the size of each chunk. The client using this information can construct the response from the chunks received by the server.
You should be using an HTTP Client library since implementing a generic HTTP client is not trivial (at all I may say).
To be specific in your code posted you should have followed one of the above approaches.
Additionally you should read in lines, since HTTP is a line terminated protocol.
I.e. something like:
BufferedReader in =new BufferedReader(new InputStreamReader( Connection.getInputStream() ) );
String s=null;
while ( (s=in.readLine()) != null) {
//Read HTTP header
if (s.isEmpty()) break;//No more headers
}
}
By sending a Connection: close as suggested by khachik, gets the job done (since the closing of the connection helps detect the end of input) but the performance gets worse because for each request you start a new connection.
It depends of course on what you are trying to do (if you care or not)
You should use existing libraries for HTTP. See here.
Your code works as expected. The server doesn't close the connection, and dataBuffer never becomes -1. This happens because connections are kept alive in HTTP 1.1 by default. Use HTTP 1.0, or put Connection: close header in your request.
For example:
out.write("GET "+ path +" HTTP/1.1\r\nHost: "+ host +"\r\nConnection: close\r\n\r\n");
out.flush();
int dataBuffer;
while ((dataBuffer = connection.getInputStream().read()) != -1)
System.out.print((char)dataBuffer);
out.close();

Winsock only sending data at program close

I have a c++/windows program that receives data from another c++ program via a WM_COPYDATA message. It is then supposed to use Sockets/winsock to send this message on to a server written in Java. The client connects to the server fine, but it doesn't seem to be able to send messages in a timely fashion. However, once the client is closed down, all the messages it should have been sending get sent in one big lump. Here is an example of the terminal output of the Java server:
Server Starting up.
Client Accepted.
hi from clienttesttesttesttesttesttesttesttesttesttesttesttesttesttest
the first two lines are output by the Java server when those events happen. The last line is messages from the client. The client sends "hi from client" right after winsock is initialized, and then "test" at various points later in the program as it receives data from the other c++ program via WM_COPYDATA messages.
Here is the Java server code:
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
String incomingLine;
while((incomingLine = in.readLine()) != null)
System.out.println(incomingLine);
Here is the c++ function where the messages are sent:
void sendDataWinsock(char* text){
int result = send(ConnectSocket,text,(int)strlen(text),0);
}
And here is a section of WndProc where the WM_COPYDATA messages are processed:
case WM_COPYDATA:
sendDataWinsock("test");
break;
Does anyone know why it is doing this? It is as if the client program is adding all these messages to a queue of things it should be sending, but is too busy to send them immediately, and so only sends them as the program is closing down, when it no longer has to process Windows messages. Or, I suppose, the error could actually be in the Java code - I am fairly new to this.
You are reading lines on the server, but you are not sending lines.
That means your server sits there, receiving data but waiting to return a line of text back to your program from readLine() , which does not happen since no newlines , \n, gets sent. When the client exits, readLine() gives you back the data it read thus far.

Server not receiving bytes written to a socket by Java app

I have the following Java socket client app, that sends same string to socket server:
import java.net.*;
import java.io.*;
public class ServerClient {
public static void main(String[] args) throws IOException {
System.out.println("Starting a socket server client...");
Socket client = new Socket("XXX.X.XXX.XX", 12001);
BufferedOutputStream stream = new BufferedOutputStream(client.getOutputStream());
String message = "ABC";
BufferedReader inputReader = new BufferedReader(new InputStreamReader(System.in));
String input = null;
while ( true ) {
System.out.print("Would you like to send a message to Server? ");
input = inputReader.readLine();
if ( !input.equals("Y") ) break;
System.out.println("Message to send: " + message);
System.out.println("Message length is: " + message.length());
byte[] messageBytes = message.getBytes("US-ASCII");
stream.write(messageBytes, 0, messageBytes.length);
stream.flush();
}
System.out.println("Shutting down socket server client...");
stream.close();
client.close();
inputReader.close();
}
}
The first time message is sent, server receives the message; however, every subsequent time I'm trying to send this message, server is not receiving anything. Message simply disappears. I am writing to the socket successfully (no exceptions) but nothing is coming on the other side of the pipe (or so I'm told).
I do not have access to the server app, logs or code, so I'm wondering if there is any approach you can recommend to figure out why server is not receiving subsequent messages. Any ideas would be greatly appreciated!
Clarification:
New lines are not expected by the server; otherwise, how would it even receive message the first time? As a trial and error, I did try sending '\n' and "\r\n" and 0x00 characters at the end of the string - all without any luck.
I thought flushing was an issue, so I tried various outputstream classes (PrintStream, PrintWriter, FilterOutputStream), but was still running into same exact issues. Then, if "flushing" is an issue, how is it working the first time?
Other tests:
1 - use a network sniffer to see what is realy hapening on the network
2 - use some program like TCP Test Tool to send data to the server and simulate your program. (netcat can also be used, but it sends a newline after each line)
Remember:
TCP is stream oriented. not message oriented.
One write on the client could take several reads on the server to .. read
Multiple writes on the client could get read by the server in one read
You'll hardly see the above scenarios in a test application on a local network, you will see them very quick in a production environemnt, or when you start to really speed up the sending/receiving.
Following this, if you are sending messages you need a delimiter, or some other way of indicating 'here's one message', e.g. defining the protocol to be 'the first byte is the length of the following message'.
And you'd need to check the receiving end wether it read a partial message, a whole message, and any combination thereof (e.e.g one read might have read 3 and a half message..).
A quick solution for your test app, write lines. That is, a string followed by a newline character. A bufferedreader's ReadLine() could then take care of the reassembly for you on the receiving end.
It works correctly here... but I am missing a carriage return or some other end of message after sending the message.
Hard to write more without knowing what the server expects (protocol)...
Maybe you should try something like
String message = "ABC\n";

Categories

Resources