I have written the code for sending/receiving data from a client socket. The sending data step has been done successfully, but when I want to read the data from a socket, the readLine() method block program while there isn't data to be read.
This is my code:
StringBuffer document = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null)
document.append(line + "\n");
reader.close()
thanks all
I can read all received data, but readLine or read(byte[], int, int) methods block program when there is no data to read, while this method must return null/-1 in this time.
That's because the readLine() function is a blocking call, so of course it's going to block.
To be more constructive, calls to methods like readLine() should be in a separate thread so that the blocking call does not affect the rest of your code. From the class which is reading, I would recommend creating a thread purely to control reading from the socket.
I would pass a reference to the creating class so that if the thread receives information, the parent class can use it.
BufferedReader has a method called 'ready()' which returns true when data is ready to be received. If you don't want to be blocked at 'readLine()' call, check first if data is ready to be read.
Have a look at the documentation.
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 have snippet
try {
is = new BufferedReader(new inputStreamReader(getSocket().getInputStream()));
}
catch(IOException e) {}
while(true) {println(is.readLine());}
Basically, I'm tring to println every single message that is sent to the input stream of the socket returned from getSocket().
My question is:
If there is no message sent to the socket, what value is returned
from calling the readLine() method? Is it the null value or a null
string (i.e. "") or is it something else?
When a message has been
sent and has been printed out, what happened to the input stream of
the socket then? Is it emptied out?
Do we need a way to check to
only call the println() method only when the input stream HAS
something to print out?
If nothing is sent through the stream - there is nothing to read yet. Your reader is just waiting.
It is emptied out only from the data you have received.
You should have the while(true) loop which is trying to read the line from the stream. You do not have to check anything.
If the socket is closed at the second side, reader is reading null. If the second side has exited without closing the socket, you get IOException.
If there is no message sent to the socket, what value is returned from calling the readLine() method? Is it the null value or a null string (i.e. "") or is it something else?
Neither. It blocks.
When a message has been sent and has been printed out, what happened to the input stream of the socket then? Is it emptied out?
No. The data received has been removed from it. There may be further pending data waiting be read.
Do we need a way to check to only call the println() method only when the input stream HAS something to print out?
No. It blocks until a line has been received, end of stream occurs, or an IOException is thrown.
Your read loop isn't correct. It doesn't detect end of stream. The usual way to write it is:
while ((line = in.readLine()) != null)
// ...
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.
Using android 2.3.3, I have a background Service which has a socket connection. There's a Thread that's reading from the socket continuously:
BufferedReader in = new BufferedReader(new InputStreamReader(mSock.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
... do stuff
}
// Socket has been closed (?)
in.close();
And then in my main thread I call:
private void writeSocket(String line) {
mSock.getOutputStream().write(line.getData("US-ASCII"));
}
When I call writeSocket, the write() does not throw an exception but I don't see the data at the other end, and the in.readLine() in the reading thread immediately returns null when the write() occurs. From what I read, it should be safe to read and write simultaneously with the same socket from different threads? It seems like the write is causing the socket to close, but I don't get an exception..
Most likely, the other end of the connection was closed normally. This causes both the read and write to terminate. (Normally, so no exception. It's just like trying to read past the end of a file.) You can read and write simultaneously from different threads and if the socket closes, whether normally or exceptionally, both operations will fail.
I have the following example of reading from a buffered reader:
while ((inputLine = input.readLine()) != null) {
System.out.println("I got a message from a client: " + inputLine);
}
The code in the loop println will be executed whenever something appears in the buffered reader (input in this case). In my case, if a client-application writes something to the socket, the code in the loop (in the server-application) will be executed.
But I do not understand how it works. inputLine = input.readLine() waits until something appears in the buffered reader and when something appears there it returns true and the code in the loop is executed. But when null can be returned.
There is another question. The above code was taken from a method which throws Exception and I use this code in the run method of the Thread. And when I try to put throws Exception before the run the compiler complains: overridden method does not throw exception. Without the throws exception I have another complain from the compiler: unreported exception. So, what can I do?
When the socket on the other end is closed, the reader should return a null string. This is the condition that you are looking for. To handle the exception, wrap the reading loop in a try/catch block.
try {
while ((inputLine = input.readLine()) != null) {
System.out.println("I got a message from a client: " + inputLine);
}
}
catch (IOException e) {
System.err.println("Error: " + e);
}
You might find this tutorial on reading/writing from/to a socket in Java, helpful.
For your first question:
But I do not understand how it works. inputLine = input.readLine() waits until something appears in the buffered reader and when something appears there it returns true and the code in the loop is executed. But when null can be returned.
BufferedReader.readLine() does not return true upon success. It returns a String containing the line that was read. If the end of the stream is reached, it returns null.
Your second question:
The above code was taken from a method which throws Exception and I use this code in the run method of the Thread. And when I try to put throws Exception before the run the compiler complains: overridden method does not throw exception. Without the throws exception I have another complain from the compiler: unreported exception. So, what can I do?
You should wrap your code in a try/catch block. If you don't want to handle the caught exception, simply leave that part blank (not recommended)
try {
while ((inputLine = input.readLine()) != null) {
System.out.println("I got a message from a client: " + inputLine);
}
} catch (Exception e) {
//handle exception
}
The reader's readLine() will return a string value when it has something read, an empty string when there isn't anything yet, and null when the connection is closed.
I would recommend wrapping a try/catch around your block of code with the IO function and handle errors appropriately.
input reader is connected to the socket, which is a listener, i.e. keeps listening to incoming messages.
About your second question, you should put a try/catch block inside the method, catch the Exception and handle it. Do not re-throw it.
But I do not understand how it works. .... waits until something appears in the
buffered reader and when something
appears there it returns true
No, it returns the value of the expression (inputLine = input.readLine()), the inputLine itself. The inputLine is compared to null.
null is returned when the "EOF (End Of File)" is reached. Since this is reading from a network socket, the end of file is created when the socket is disconnected (either by the server or the client), but you will likely get an Exception before you actually see the EOF.
If this isn't for homework, you might want to look at Apache Commons IOUtils.
Assuming you don't create the BufferedReader, and just stop at the InputStream:
String results = IOUtils.toString(inputStream);
System.out.println(results);
while ((inputLine = input.readLine()) != null) {
Look at each part of the expression:
input.readLine()
Returns a String which will be null if the end of the stream has been reached (or throws an Exception on error).
inputLine = input.readLine()
Assigns this String to inputLine
((inputLine = input.readLine()) != null)
Checks that the String that was assigned is not null (end of stream).
You have received some good answers. Just catch the exception and deal with it locally. If you need to pass this on to other code but cannot since the run() method does not allow for any check exception, you can wrap the exception in a RuntimeException of some kind. If the run method is executing directly on a Thread (since it is a Runnable probably) then you should take care with re-throwing a wrapped exception.
As for the result from readLine(), it will return null when there is nothing more to read. In the case of a socket this is when the other side cleanly closes the socket (any sudden termination or unclean close would typically result in an exception in your code as the OS will send a different kind of socket close notification).
I do have one word of caution since you are wrapping a socket in a java.io.BufferedReader. You should be very careful about using this in any kind of production code.
The danger is that BufferedReader does not deal well with exceptions in the midst of reading. This is especially an issue if you have enabled a timeout on the socket so the code will receive periodic exceptions automatically from the operating system. The timeout (or other exception) could come while the buffer inside the reader is filling. If you attempt to reuse the object after the exception, it will ignore any previous contents in the buffer. The packet(s) that were previously received are silently lost and there is no way to retrieve those bytes.
Note that there are other kinds of socket exceptions that do not mean that the socket has been lost. For instance, look at the definition of java.io.InterruptedIOException. This has a public variable that reports the number of bytes successfully transferred in the most recent I/O (read or write) request. This means that the IO operation can be executed again to retrieve or send the remaining bytes for the packet.
If upon any exception your design is to immediately close the reader and socket the method will work correctly.
The proper way to read from a socket is to use the socket stream directly, use NIO (ByteBuffers and such), or use a well written network library with good abstractions over these lower level classes (several open source ones are available).