I am making a client socket connection with a hardware device. I am sending a command to this connection to be process by hardware. Now as a acknowledgment or as a reply, the hardware sends a response.
The application sends a command to the connection periodically say in 10 seconds.
Now there exists a problem randomly that the response won't gets synchronized with the sent command from the application. I was thinking of this as hardware specific but to my surprise, when I see the response by connecting putty to the same hardware at same port, I can see that response always gets synchronized. This looks like putty under the hood using some criteria to map the request to response.
Below is the programming steps that I am using to send a command to hardware device:-
Socket clientSocket = new Socket(<IPADDRESS>, 4001);
DataOutputStream outToServer = new DataOutputStream(
clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
while (true) {
try {
//Get command randomly from array enums for test
Random r = new Random();
Commands[] array = Commands.values();
String command = (String) array[r
.nextInt(Commands.values().length)].getCommand();
outToServer.writeBytes(command);
Thread.sleep(500);
while (!inFromServer.ready()) {
}
System.out.println("COMMAND "+command+", SERVER RESPONSE: "
+ inFromServer.readLine());
Thread.sleep(1500);
} catch (SocketTimeoutException se) {
//Handle Exception
} catch (SocketException se) {
//Handle Exception
}
Can anybody gives a advice how the synchronization of response with request can be achieved as mechanism like putty?
Putty doesn't know any more about your device than you do. The problem is in your code. Get rid of the ready() test and the sleep(). Just call readLine(), if you can be sure that the device sends lines, otherwise just call InputStream.read().
Remove the thread sleep, and rewrite read like this:
String line;
while ((line = inFromServer.readLine()) != null) {
System.out.println("COMMAND "+command+", SERVER RESPONSE: "
+ line);
}
This code can still hang, if the device sends the last message without the newline character \n. Your original code skipped the input.
The main problem is with this line:
while (!inFromServer.ready()) {
InputStreamReader#ready is OK to use only when you have other means to know that all the data has been sent:
Tells whether this stream is ready to be read. An InputStreamReader is ready if its input buffer is not empty, or if bytes are available to be read from the underlying byte stream.
The first message will get read, but that empties the buffer, and when the second message arrives your code isn't reading anymore. You would have to have as many loops as there are messages from device, and that's not practical, at least. And in that case also, it would probably not work all the time.
On the other hand the BufferedReader#readLine:
Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
will read until all the data that was sent has been read. But if your device send no new line character, then this method will never read the line - the code will hang with all the data in the buffer. In that case you should use InputStreamReader#read as EJP suggested:
Returns:
The character read, or -1 if the end of the stream has been reached
I strongly suggest that you read the IO Streams official tutorial.
Generally speaking, waiting is not done by Thread.sleep and busy waiting (executing empty statements), e.g.:
while (true) {} /*or*/ while(true);
The CPU is executing the empty statement, and it could be doing some other work while waiting on this one to complete. It is a bad practice.
If you want to know more on how to implement waiting I recommend reading the official concurrency tutorial or this one for a broader approach on the matter.
Related
I have been trying to send a byte[] array across my client / server application using Sockets, DataInputStream and DataOutputStream, but on the server side, the program just gets stuck when I try to initialise the DataInputStream.
Here is the code on the client side (it works fine):
DataOutputStream datas = new DataOutputStream(connection.getOutputStream());
datas.flush();
byte[] send = identityKeyPair.serialize();
datas.write(send);
datas.flush();
Here is the code on the server side:
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()) );
sender = new PrintWriter(connection.getOutputStream());
newUser = new BasicUserData();
System.out.println("New registration from: " + connection.getInetAddress());
System.out.println("Data:");
String un = reader.readLine();
newUser.USERNAME = un;
System.out.println(newUser.USERNAME);
String pw = reader.readLine();
newUser.PASSWORD = pw;
System.out.println(newUser.PASSWORD);
DataOutputStream dataout = new DataOutputStream(connection.getOutputStream());
System.out.println("Opened data output stream");
DataInputStream receiver = new DataInputStream(connection.getInputStream());
//It gets stuck here, and the program doesn't read anything further
receiver.read();
byte[] id = receiver.readAllBytes();
System.out.println("Opened data input stream");
You are using both connection.getInputStream() and connection.getOutputStream() in two different ways. You should use one and only one way of reading from and writing to streams, don't mix multiple ways.
When you execute reader.readLine(), the BufferedReader called reader will read up-to 8192 characters from the input stream into its buffer, likely consuming all bytes your client has written. This means that when you construct your DataInputStream around that same input stream and try to read it, there is no data available to read, causing the receiver.read() to block waiting for data. That data is never received as your client has sent all its data, which is now buffered in reader.
In addition, unless your client has closed its output stream, InputStream.readAllBytes() will block indefinitely anyway, because it is only finished when the end-of-stream has been reached. And for socket communication, that only happens when the other side closed its output stream.
Change your code so there is only one way of writing data (though not relevant here), and one way of reading data. In addition, you should establish clearly how you need to read and write data in a protocol, so to avoid consuming too much data at the wrong point, and to know how much data you need to read when.
Of course it does nothing but wait as specified in the javadoc a call to DataInputStream#read() blocks the current thread until data can be read from the input stream.
Your reader = BufferedReader(...) uses the same underlying InputStream which means the all the data the client sent is most likely already consumed by the 'login' logic.
Since neither the client nor the server close their respective streams no EOF is emitted either which leads to the stream 'just dangling' around waiting for more data.
Unless your client sends more data the server will wait eternally.
There are two solutions for your issue.
Either thread you application so that the 'await input' logic is in it's own thread or take a look at javas NIO package (more precisely Channels and Selectors)
I'm currently working on a project where i have to host a server wich fetches an inputstream, parses the data and sends it to the database. Every client that connects to my server sends an inputstream wich never stops once it is connected. Every client is assigned a socket and its own parser thread object so the server can deal with the datastream coming from the client. The parser object just deals with the incoming data and sends it to the database.
Server / parser generator:
public void generateParsers() {
while (keepRunning) {
try {
Socket socket = s.accept();
// new connection
t = new Thread(new Parser(socket));
t.start();
} catch (IOException e) {
appLog.severe(e.getMessage());
}
}
}
Parser thread:
#Override
public void run() {
while (!socket.isClosed() && socket.isConnected()) {
try {
BufferedReader bufReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = bufReader.readLine();
String data = "";
if (line == null) {
socket.close();
} else if (Objects.equals(line, "<DATA")) {
while (!Objects.equals(line, "</DATA>")) {
data += line;
line = bufReader.readLine();
}
/*
Send the string that was build
from the client's datastream to the database
using the parse() function.
*/
parse(data);
}
}
} catch (IOException e) {
System.out.println("ERROR : " + e);
}
}
}
My setup is functional but the problem is that it delivers too much stress on my server when too much clients are connected and thus too many threads are parsing data concurrently. The parsing of the incoming data and the sending of the data to the database is hardly effecting the performance at all. The bottleneck is mostly the concurrent reading of the client's datastreams from the connected clients.
Is there any way that i can optimize my current setup ? I was thinking of capping the amount of connections and once a full datafile is recieved, parse it and move to the next client in the connection que or something similar.
The bottleneck is mostly the concurrent reading
No. The bottleneck is string concatenation. Use a StringBuffer or StringBuilder.
And probably improper behaviour when a client disconnects. It's hard to believe this works at all. It shouldn't:
You should use the same BufferedReader for the life of the socket, otherwise you can lose data.
Socket.isClosed() and Socket.isConnected() don't do what you think they do: the correct loop termination condition is readLine() returning null, or throwing an IOException:
while ((line = bufReader.readLine()) != null)
Capping the number of concurrent connections can't possibly achieve anything if the clients never disconnect. All you'll accomplish is never listening to clients beyond the first N to connect, which can't possibly be what you want. 'Move to the next client' will never happen.
If your problem is indeed that whatever you are doing while client is connected is expensive, you will have to use client queue. The most simple way to do this will be to use ExecutorService with N numer of max threads.
For example
private ExecutorService pool=Executors.newFixedThreapPool(N);
...
and then
Socket socket = s.accept();
pool.submit(new Parser(socket)));
This will limit concurent client handling to N at the time, and queue any additional clients that exceeds N.
Also depends on what you are doing with the data, you could always split the process to phases for example
Read raw data from client and enqueue for processing - close socket etc. so you can save resources
Process the data in separate thread (possibly thread pool) and enqueue the result
Do something with the result (check for validity, persist into DB etc) in another pool.
This is especially helpfull if you got some blocking operations like network I/O, or expensive one etc.
Looks like in your case, client does not have to wait for whole backend proess to complete. He only needs to deliver the data, so splitting data reading and parsing/persisting into separate phases (subtasks) sounds like reasonable approach.
I am currently implementing a web proxy but i have run into a problem.I can parse my request from the browser and make a new request quite alright but i seem to have a problem with response.It keeps hanging inside my response loop
serveroutput.write(request.getFullRequest());
// serveroutput.newLine();
serveroutput.flush();
//serveroutput.
//serveroutput.close();
} catch (IOException e) {
System.out.println("Writting tothe server was unsuccesful");
e.printStackTrace();
}
System.out.println("Write was succesful...");
System.out.println("flushed.");
try {
System.out.println("Getting a response...");
response= new HttpResponse(serversocket.getInputStream());
} catch (IOException e) {
System.out.println("tried to read response from server but failed");
e.printStackTrace();
}
System.out.println("Response was succesfull");
//response code
public HttpResponse(InputStream input) {
busy=true;
reader = new BufferedReader(new InputStreamReader(input));
try {
while (!reader.ready());//wait for initialization.
String line;
while ((line = reader.readLine()) != null) {
fullResponse += "\r\n" + line;
}
reader.close();
fullResponse = "\r\n" + fullResponse.trim() + "\r\n\r\n";
} catch (IOException`` e) {
e.printStackTrace();
}
busy = false;
}
You're doing a blocking, synchronous read on a socket. Web servers don't close their connections after sending you a page (if HTTP/1.1 is specified) so it's going to sit there and block until the webserver times out the connection. To do this properly you would need to be looking for the Content-Length header and reading the appropriate amount of data when it gets to the body.
You really shouldn't be trying to re-invent the wheel and instead be using either the core Java provided HttpURLConnection or the Appache HttpClient to make your requests.
while (!reader.ready());
This line goes into an infinite loop, thrashing the CPU until the stream is available for read. Generally not a good idea.
You are making numerous mistakes here.
Using a spin loop calling ready() instead of just blocking in the subsequent read.
Using a Reader when you don't know that the data is text.
Not implementing the HTTP 1.1 protocol even slightly.
Instead of reviewing your code I suggest you review the HTTP 1.1 RFC. All you need to do to implement a naive proxy for HTTP 1.1 is the following:
Read one line from the client. This should be a CONNECT command naming the host you are to connect to. Read this with a DataInputStream, not a BufferedReader, and yes I know it's deprecated.
Connect to the target. If that succeeded, send an HTTP 200 back to the client. If it didn't, send whatever HTTP status is appropriate and close the client.
If you succeeded at (2), start two threads, one to copy all the data from the client to the target, as bytes, and the other to do the opposite.
When you get EOS reading one of those sockes, call shutdownOutput() on the other one.
If shutdownOutput() hasn't already been called on the input socket of this thread, just exit the thread.
If it has been called already, close both sockets and exit the thread.
Note that you don't have to parse anything except the CONNECT command; you don't have to worry about Content-length; you just have to transfer bytes and then EOS correctly.
I am currently working on a simple proxy server, which receives http request from browser, process it, then forward it to the desire web server.
I try to get the request from the input stream of the socket connected by the browser, everything is fine except that the stream get stuck after receiving the last block of data.
My code is in fact very simple, as shown below:
ServerSocket servSocket = new ServerSocket(8282);
Socket workSocket = servSocket.accept();
InputStream inStream = workSocket.getInputStream();
byte[] buffer = new byte[1024];
int numberRead = 0;
while ((numberRead = inStream.read(buffer, 0, 1024)) != -1){
System.out.println(new String(buffer));
}
The loop simply cannot exit, even the request reception is finished.
Is there any method to workaround this problem?
Thanks in advance for any advice.
As in InputStream javadoc the method will block until the data is available or the EOF is encountered. So, the other side of Socket needs to close it - then the inStream.read() call will return.
Another method is to send the size of message you want to read first, so you know ahead how many bytes you have to read. Or you can use BufferedReader to read from socket in line-wise way. BufferedReader has a method readLine() which returns every time a line is read, which should work for you as HTTP protocol packages are nice divided into lines.
It will cycle until the connection is closed, and the client is probably waiting for HTTP response from you and doesn't close it.
The browser is waiting for a response before it closes the connection.
Your read-method on the other hand will block until the stream/connection is closed or new data is received.
Not a direct solution according to your current code.
As HTTP is a line based protocol, you might want to use a Buffered Reader and call readLine() on it.
The when a http request comes in it will always be concluded with a blank line, for example:
GET /someFile.html HTTP/1.1
Host: www.asdf.com
After sending that request the client connection will then wait for a response from the server before closing the connection. So if you want to parse the request from the user you are probably better off using a BufferedReader and reading full lines until you reach a lines of text that is blank line.
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";