I have a thread in which the read() method of an InputStream is called in a loop. When there are no more bytes to read, the stream will block until new data arrives.
If I call close() on the InputStream from a different thread, the stream gets closed, but the blocked read() call still remains blocked. I would assume that the read() method should now return with a value of -1 to indicate the end of the stream, but it does not. Instead, it stays blocked for several more minutes until a tcp timeout occurs.
How do I unblock the close() call?
Edit:
Apparently, the regular JRE will throw a SocketException immediately when the stream or socket the blocking read() call corresponds to is close()'d. The Android Java runtime which I am using, however, will not.
Any hints on a solution for the Android environment would be greatly appreciated.
Only call read() when there is data available.
Do something like that:
while( flagBlock )
{
if( stream.available() > 0 )
{
stream.read( byteArray );
}
}
set the flagBlock to stop the reading.
See Java Concurrency In Practice for a really good system to cancel a thread when working with sockets. It uses a special executor (CancellingExecutor) and a special Callable (SocketUsingTask).
When the other end closes the connection your stream will return -1 on a read(). If you cannot trigger the other end to close the connection e.g. by closing your output stream, you can close the socket which will cause an IOException in the blocking read() thread.
Can you provide a short example which reproduces your problem?
ServerSocket ss = new ServerSocket(0);
final Socket client = new Socket("localhost", ss.getLocalPort());
Socket server = ss.accept();
Thread t = new Thread(new Runnable() {
public void run() {
int ch;
try {
while ((ch = client.getInputStream().read()) != -1)
System.out.println(ch);
} catch (SocketException se) {
System.out.println(se);
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
server.getOutputStream().write("hi\n".getBytes());
Thread.sleep(100);
client.close();
t.join();
server.close();
ss.close();
prints
104
105
10
java.net.SocketException: Socket closed
We were having the same issue: no exception when switching network (e.g. switching from 3G to WiFi while downloading).
We are using the code from http://www.androidsnippets.com/download-an-http-file-to-sdcard-with-progress-notification, which is working perfectly except in some cases when the network connection was lost.
The solution was specifying a timeout value, this is set standard to 0 (meaning: wait infinitely).
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.setReadTimeout(1000);
c.connect();
Experiment with a timeout value appropriate for you.
I had such issue on Samsung 2.3. When switching from 3G to Wifi InputStream.read() method blocks. I tried all tips from this topic. Nothing helped. From my prospective this is device specific issue because it should throw IOException due to javadoc. My solution is to listen for android broadcast android.net.conn.CONNECTIVITY_CHANGE and close connection from another thread it will cause IOException in blocked thread.
Here is code example:
DownloadThread.java
private volatile boolean canceled;
private volatile InputStream in;
private boolean downloadFile(final File file, final URL url, long totalSize) {
OutputStream out = null;
try {
Log.v(Common.TAG, "DownloadThread: downloading to " + file);
in = (InputStream) url.getContent();
out = new FileOutputStream(file);
return copy(out, totalSize);
} catch (Exception e) {
Log.e(Common.TAG, "DownloadThread: Exception while downloading. Returning false ", e);
return false;
} finally {
closeStream(in);
closeStream(out);
}
}
public void cancelDownloading() {
Log.e(Common.TAG, "DownloadThread: cancelDownloading ");
canceled = true;
closeStream(in); //on my device this is the only way to unblock thread
}
private boolean copy(final OutputStream out, long totalSize) throws IOException {
final int BUFFER_LENGTH = 1024;
final byte[] buffer = new byte[BUFFER_LENGTH];
long totalRead = 0;
int progress = 0;
int read;
while (!canceled && (read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
totalRead += read;
}
return !canceled;
}
You could use java.nio package. NIO stands for Non-blocking IO. Here the calls (to say read & write) aren't blocked. This way you can close the stream.
There is a sample program you can look at here. Method: processRead
Related
I have a thread handling a socket connection:
BufferedReader socketInput = new BufferedReader(new InputStreamReader(mySocket.getInputStream()));
while (true)
{
String line = socketInput.readLine();
// do stuff
}
As I've read in a few answers on this site, the recommended solution is to use a flag which one thread sets and my (socket handling) thread checks and terminates itself when that flag changes state. Something like:
while (!done)
{
String line = socketInput.readLine();
// do stuff
}
But this can get stuck when readLine() is still waiting for input. I guess I could set a timeout:
mySocket.setSoTimeout(100);
while (!done)
{
String line = socketInput.readLine();
// do stuff
}
Which would probably work but I would still get a 100 ms delay before my thread "realizes" the flag's state changed.
Is there a way for the thread to "realize" right away that it should end? If not, is my solution (with timeout and flag done) correct?
Edit: I've clarified that the socketInput is of type BufferedReader (alternatively I'm considering Scanner).
The most common way to handle this is to close the socket from the other Thread. This will lead the reading side to unblock and exit with the (expected) error that the socket was closed. Depending on the socket API that you have available it might also be possible to shutdown only the reading side. From a short look at the JDK shutdownInput() might work.
If you however want to continue to read from the socket later on these obvisouly won't work. Your solution should work there, but is obvisouly worse for performance and reactivity since you basically poll the socket all 100ms.
Create a Selector
Configure your socket.getChannel() to non-blocking and register it to the Selector with SelectionKey.OP_READ
Call your Selector select() method that will return when there are some data to read so you can call readLine() (i.e. select() returns > 0)
Whenever you want to end your socket processing, set your done flag and call your Selector wakeup() method. That will make the select() return immediately (potentially 0, or 1 if there was activity). You can then check your done flag and end your thread gracefully.
Here is a quick implementation. Notice I pass the BufferedReader as an argument as if you're opening it in the thread you should also close it there, which would close the socket too, so it has to be done outside. There are two methods to signal the thread to gracefully stop processing input and one to send data:
public class SocketHandler extends Thread {
private Socket sok;
private BufferedReader socketInput;
private Selector sel;
private SocketChannel chan;
private boolean done;
public SocketHandler(Socket sok, BufferedReader socketInput) throws IOException {
this.sok = sok;
chan = sok.getChannel();
chan.configureBlocking(false);
sel = Selector.open();
chan.register(sel, SelectionKey.OP_READ);
this.socketInput = socketInput;
done = false;
}
#Override
public void run() {
while (!done) {
try {
if (sel.select() == 0)
continue;
} catch (IOException e) {
e.printStackTrace();
}
// Only one channel is registered on only one operation so we know exactly what happened.
sel.selectedKeys().clear();
doRead();
// Otherwise: loop through sel.selectedKeys(), check for readability and clear the set
}
try {
sel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void doRead() {
try {
String line = socketInput.readLine();
// TODO: process 'line'
} catch (IOException e) {
e.printStackTrace();
}
}
public void signalStop() {
done = true;
if (sel != null)
sel.wakeup(); // Get out of sel.select()
}
public void doWrite(byte[] buffer) throws IOException { // Or "String message"
sok.getOutputStream().write(buffer); // Or anything else
}
}
The solution is correct, it will exit when done is set to true.
And yes, the readLine will always wait for 100ms, if you don't want to wait you may interrupt the thread by calling thread.interrupt() it but it's not very clean way.
The best way to know when finish a socket connection is to try to read something. If read method return -1 you can end threadling socket connection
byte[] data = new byte[2048];
while (!done) {
int count = input.read(data);
if (count <= 0) {
if (count < 0)
done = true;
continue;
}
String request = new String(data, 0, count);
//do stuff
}
We try to read something in input if count == -1, the socket client is disconnected now we can end the loop, by changing the value of done.
Basically the server side sends a keep alive message every 8 minutes, if the write fails it disconnects the client and closes the socket connection. If my android device is awake and the server closes the connection then the read operation on the android device throws an exception as it should and i disconnect from the server. If the device is asleep it doesn't read data at all even with a partial wake lock and a wifilock, i have already given up on that, but my actual problem is when my device comes back from sleep (if i turn the screen on for example) what i do is send a message to the server so i can refresh the data but if my server has already closed the socket my write operation should throw an IOException but for some reason it doesn't. And even the blocking read i have doesn't throw any exception or return -1.
here is my write operation:
public boolean sendData(byte[] data)
{
boolean sent=false;
if(connectedToServer)
{
try
{
myOutputStream.write(data, 0, data.length);
sent= true;
}
catch (IOException e)
{
e.printStackTrace();
unexpectedDisconnectionFromServer();
}
}
return sent;
}
and here is my read operation:
public void startReadingInBackground()
{
while(connectedToServer)
{
try
{
int bytesRead=0;
if(myWifiLock!=null && !myWifiLock.isHeld())
myWifiLock.acquire();
byte val=(byte)myInputStream.read();
myWakeLock.acquire();
if(val==-1)
{
unexpectedDisconnectionFromServer();
if(myWifiLock!=null && myWifiLock.isHeld())
myWifiLock.release();
myWakeLock.release();
return;
}
bytesRead=myInputStream.read(myBuffer, 0, bufferSize);
if(bytesRead<1)
{
unexpectedDisconnectionFromServer();
if(myWifiLock!=null && myWifiLock.isHeld())
myWifiLock.release();
myWakeLock.release();
return;
}
byte[] dataArray=Arrays.copyOfRange(myBuffer,0,bytesRead);
ByteBuffer data=ByteBuffer.allocate(bytesRead+1).put(val).put(dataArray);
myParent.invokeReceiveAction(data, bytesRead + 1);
}
catch (IOException e)
{
if(!myWakeLock.isHeld())
myWakeLock.acquire();
unexpectedDisconnectionFromServer();
e.printStackTrace();
}
finally
{
if(myWifiLock!=null && myWifiLock.isHeld())
myWifiLock.release();
if(myWakeLock!=null && myWakeLock.isHeld())
myWakeLock.release();
}
}
}
and i get the outputstream like so:
Socket mySocket = new Socket(SERVER_IP, SERVER_PORT_TCP );
myOutputStream=mySocket.getOutputStream();
Your write will throw an IOException, eventually. Your mistake is in assuming it is bound to happen on the first write after the disconnect. It won't, for all sorts of reasons including buffering and retries. TCP has to determine that the connection is really dead before it will reject a new write, and it certainly won't do that on the first write after the disconnect.
I am trying to write a thread which will do following stuffs:
1. read from inputstream;
2. some other routine;
3. if socket is closed, throw an exception.
The BlueTooth Socket and inputStream from the socket has been set up before this. The code is as following:
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
//if(mInputStream.available() > 0){ //-------- Line 1
bytes = mInputStream.read(buffer);
//} //-------- Line 2
//---------------------//
// some other routines //
//---------------------//
} catch (IOException e) {
connectionLost();
break;
}
}
}
The problem is that the above code will hang at mInputStream.read() because of the blocking. However, if I uncomment Line 1 and Line 2, the mInputStream.available() function will not throw exception even if BlueToothSocket is closed. Is there any method either to unblock read function, or to throw an exception when available() is used and BlueTooth Socket is closed? Appreciate it!
This is what I use:
private boolean receivedInTimelyManner(InputStream mInStream,
int bytesToReceive, long timeoutMillis) throws IOException,
InterruptedException {
long time = 0;
while (mInStream.available() < bytesToReceive && time < timeoutMillis) {
time+=5;
Thread.sleep(5);
}
if (time == timeoutMillis) {
return false;
}
return true;
}
Surround your read block with something like:
if receivedInTimelyManner(instream,bytes,timeout){
read()
}
Ok, seems there is not an easy way to do unblocked read() and available() throwing is not working. The most convenient way to work this out is to create another thread to do the other routines. While leave this thread alone particularly for reading inputstream and checking inputstream status(exception thrown).
I have written the code below, but after calling almost 150 times, it throws "Exception in thread "Thread-245" java.lang.OutOfMemoryError: Java heap space" the problem just ocure in (b = new byte[1024 * 1024];)
Java Code:
class Client implements Runnable {
private Socket socket;
private BufferedInputStream bufin = null;
private BufferedOutputStream bufout = null;
String path;
private byte[] b;
Client(Socket socket, String path) {
this.socket = socket;
this.path = path;
}
#Override
public void run() {
try {
bufin = new BufferedInputStream(socket.getInputStream());
bufout = new BufferedOutputStream(new FileOutputStream(path));
b = new byte[1024 * 1024];
int num = 0;
while ((num = bufin.read(b)) != -1)
bufout .write(b, 0, num);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufin.close();
bufout .close();
b = null;
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I try to describe the problem more clearly. it is like this:
I write i ServerSocket, when a client send the request the Sever then put the request in a new thread as below:
public void start() {
boolean started = false;
try {
ServerSocket ss = new ServerSocket(8888);
started = true;
while (started) {
String path = "C:/Pic/"+ new SimpleDateFormat("yy-MM-dd-HH_mm_ss_ms").format(new Date()) + ".jpg";
Socket s = ss.accept();
new Thread(new Client(s, path)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
in this case the Server will recieve the request from any client...
and also the second problem which i think that problem will cause the Java heap space Exception, that is when the Server recieve the picture, then the picture can not be deleted from the disk before you close the server, when i delete it,
it says "The action can't be completed because the file is open in Java(TM) platform SE Binary". Whereas i have already closed the input output in Client thread.
Now i can not discover the root of the problem, 1. why happen Heap Exception anr 2. why the file is not deletable from disk during server is running.
Thanks alot in advance of your reply!
You're running out of memory because each thread is creating a 1MB array buffer. You want to see what the max heap size is (this depends on a few variables) and increase your max size at the command line, example:
java -Xmx1024M myclass.class
Also, you said you started 150 clients. Why are they not getting garbage collected? Perhaps all 150 are starting instantly and all threads are grabbing for that memory at the same time? I recommend using a thread pool to execute these so you can put a limit on the running client count.
For your problem with the server holding the file (you can't delete it) is because you're getting that heap memory error. All bets are off when you get this. The server is still holding reference to the file and the bufout.close() probably did not work.
I suspect that the heap exhausted does not allow the program to operate properly after the exception occours and then in the finally block, leaving stream open. I suggest you change the program to allocate the memory block before opening the stream; in addition, to close the streams in the finally block I suggest you use the class IOUtils commons-io as described in the example:
closeQuietly
byte[] data = "Hello, World".getBytes();
OutputStream out = null;
try {
out = new FileOutputStream("foo.txt");
out.write(data);
out.close(); //close errors are handled
} catch (IOException e) {
// error handling
} finally {
IOUtils.closeQuietly(out);
}
This allows you to be sure that all streams are closed in the finally block.
I'm reading messages from a socket (trough a TCP protocol), but I note that the CPU spend a lot of time to call the method available() of my BufferedInputStream. This is my code:
#Override
public void run()
{
Socket socket;
Scanner scanner;
BufferedInputStream buffer = null;
try
{
socket = new Socket(SERVER_HOST, SERVER_PORT);
System.out.println("Connection Completed");
InputStream inputStream = socket.getInputStream();
buffer = new BufferedInputStream(inputStream);
StringBuilder readCharacter;
while (true)
{
readCharacter = new StringBuilder();
try
{
while (buffer.available() > 0)
{
readCharacter.append((char) buffer.read());
}
}
catch (IOException e)
{
e.printStackTrace();
buffer.close();
}
String array[] = separe(new String(readCharacter));
... //parsing the message
I've also tried to use int read=buffer.read() and check if (read!=-1) instead of using the available function, but in this case I'm not able to recognize the end of the message...in my StringBuilder 'readCharacter' I have more than one message, one after the other..and it cause the fail of my parsing process...
Instead using the available() check, into the readCharacter I have only one message at a time..and the parsing works...
Can you help me to understand why, and how avoid the eating of CPU?
This loop:
while (buffer.available() > 0)
{
readCharacter.append((char) buffer.read());
}
can be replaced with simple:
readCharacter.append((char) buffer.read());
Instead of calling non-blocking available() over and over again (which consumes a lot of CPU) just call read() which will block not consuming CPU until something is available. Looks like this is what you want to achieve with less code and complexity.
The available() itself does not eat CPU. What does it is your loop:
while (buffer.available() > 0) {
readCharacter.append((char) buffer.read());
}
While bytes are unavailable you are actually calling available() multiple times (probably thousands of times). Since read() method of streams is blocking you do not have to call available() at all. The following code does the same but does not eat CPU.
String line = null;
while ((line = buffer.read()) != null) {
readCharacter.append(line);
}