My favorites | Sign in
Project Home Issues
New issue   Search
for
  Advanced search   Search tips   Subscriptions
Issue 7933: Closing a socket from another thread doesn't generate IOException
27 people starred this issue and may be notified of changes. Back to list
Status:  Released
Owner:  e...@google.com
Closed:  Aug 2010
Cc:  b...@google.com, e...@google.com, jessewil...@google.com

Restricted
  • Only users with Commit permission may comment.


Sign in to add a comment
 
Reported by blahblah676, Apr 23, 2010
Running on avd platform 2.1 api 7.

thread 1 is blocking on DataInputStream.readByte() (from a tcp socket)
thread 2 closes the DataInputStream and then closes the Socket
thread 1 never receives an IOException like it should. Instead the
readByte() just keeps blocking (or, if you pause the blocking thread in the
debugger, it seems to return immediately with a garbage value)

My IOException catch block is correctly called when the remote server
closes the connection, so I don't think there is a problem with the code.

Code skeleton:

class NetworkThread extends Thread
{
    DataInputStream is;
    DataOutputStream os;
    Socket server;

    // first thread - waiting for data from server (is, os and server
    // have been set up and are connected to a normal, blocking tcp Socket
    // to a remote server)
    public void run()
    {
        for (;;)
        {
            if (connected)
            {
                try
                {
                    int set_type = is.readUnsignedByte();
                    // if the socket is closed during the readUnsignedByte
                    // call we should get an IOException
                    ...

    // This is the second thread, which will close the socket while the
    // first thread is blocked in readUnsignedByte
    Handler handler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            switch (msg.what)
            {
            case messages.DISCONNECT_FROM_SERVER:
                try
                {
                    os.close();
                    is.close();
                    server.close();
                }
                catch (IOException e)
                {
                }

                os = null;
                is = null;
                server = null;

                ...




Apr 23, 2010
Project Member #1 e...@google.com
(No comment was entered for this change.)
Labels: Component-Dalvik
Jun 9, 2010
Project Member #2 e...@google.com
 Issue 8097  has been merged into this issue.
Jun 10, 2010
#3 blahblah676
Just wondering if this is just a bug in the emulator or if it happens on the phones as well. I don't have an Android phone to test on. If the problem does happen on the phones then it is pretty much a show-stopper for our app unless we can figure out a workaround (I'm thinking it might be possible to interrupt the blocked thread, but haven't tried it yet).

Also, let me know if you need a full a full sample app to recreate the problem and I can knock something up.
Jun 11, 2010
#4 balb...@gmail.com
As far as can tell you this bug appears on phone as well. Please let me know i you have any idea how to kill blocked thread
Jun 11, 2010
#5 blahblah676
I just tried Thread.interrupt, but that doesn't have any effect. When I compile, the compiler says that the 'catch InterruptedException' is unreachable code (because the socket read operation never throws it).

Another possible solution would be to use setSOTimeout so that the read operations only block for a certain period of time rather than blocking indefinitely.
Jun 12, 2010
#6 balb...@gmail.com
I even tried Thread.stop (I know that it's deprecated and not recommended) but still no results. Moreover I added StreamWrapper (see attached file) and I noticed interesting thing. When I do not implement read(byte[] b, int offset, int length) method, read() method is called infinity times. When read(byte[] b, int offset, int length) method is implemented application hangs on.
 
StreamWrapper.java
1.6 KB   View   Download
Jun 15, 2010
#7 blahblah676
I tried using Socket.setSoTimeout(), and that seems to work. I think that is the only workaround. I am doing this in my read loop:

server.setSoTimeout(1000);
packet_type = input_stream.readUnsignedByte();
server.setSoTimeout(0);
// read rest of data

You just need to be careful that, if you are closing the socket and opening it again, you wait until your read thread has timed out.
Jun 22, 2010
#8 blahblah676
Also, I discovered that sometimes the read simply returns garbage rather then firing the SocketTimeoutException, so you need to check to make sure the socket is connected before reading the rest of the data.

And of course, this hacky workaround will break completely if the other thread happens to close the socket while in the middle of reading the rest of the data.
Jul 4, 2010
#9 dclo...@gmail.com
I've seen this problem as well, but was able to work around it by calling shutdownInput() on the Socket before calling close().
Jul 5, 2010
#10 blahblah676
I just tried shutdownInput() and it works perfectly - thanks for the simple workaround!
Jul 23, 2010
Project Member #11 e...@google.com
(No comment was entered for this change.)
Owner: e...@google.com
Jul 23, 2010
Project Member #12 e...@google.com
 Issue 7496  has been merged into this issue.
Jul 23, 2010
#13 fas...@gmail.com
The merged issue ( Issue 7496 ) covers a serious side-effect of this bug.  Namely that it's not possible to shut down a DefaultHttpClient without somehow getting hold of the underlying Socket and calling its shutdownInpput method.
Aug 10, 2010
#14 jessewil...@google.com
Fixed by enh. Tracked internally by http://b/2823977
Status: FutureRelease
Aug 17, 2010
#15 deepa.su...@gtempaccount.com
Where is this fix available. searched in android.git.kernel.org ; we could not locate the fix. Can you provide the URL.

Thanks
Aug 17, 2010
Project Member #16 e...@google.com
the fix will be in gingerbread.
Labels: Target-Gingerbread
Oct 6, 2010
#17 jessewil...@google.com
 Issue 11705  has been merged into this issue.
Cc: e...@google.com
Dec 6, 2010
Project Member #18 e...@google.com
(No comment was entered for this change.)
Status: Released
May 16, 2011
#19 maurice....@commzgate.com
The shutdownInput() workaround does not wrok for 2.2.2. It just ignores everything without throwing exception. Any workarounds?
May 16, 2011
Project Member #20 e...@google.com
yeah, i wouldn't expect shutdown(2) to be reliable. the best pre-gingerbread workaround is a combination of extra threads and timeouts.
May 17, 2011
#21 maurice....@commzgate.com
Another discovery, Thread.interrupt does nothing to an I/O Blocking read as well. InterruptedException is never thrown.
May 18, 2011
Project Member #22 e...@google.com
@21: it's a little more complicated than that... Thread.interrupt _will_ interrupt java.nio I/O but _not_ java.io I/O. this behavior is consistent with the RI. i have an internal bug to look at making this work for both on Android, but haven't had time yet.
Cc: b...@google.com jessewil...@google.com
May 18, 2011
#23 maurice....@commzgate.com
Hmmm I'm currently using an ObjectInputStream and ObjectOutputStream for Socket communication, so is there any workaround for exiting the blocking thread since shutdowniput(), shutdownoutput(), close(), thread.interrupt() don't work? Would like to confirm this before I do a major change to my code because the following cannot be performed.
May 19, 2011
Project Member #24 e...@google.com
@23: unless you're only planning on supporting >= gingerbread, all the workarounds basically involve rewriting your code one way or another.
May 19, 2011
#25 blahblah676
enh: can you just clarify what you mean by "a combination of extra threads and timeouts"? Perhaps I'm missing something, but as I understand it the problem is that nothing can interrupt the thread that is blocking on socket IO - so how can extra threads help?

Also, when you say 'timeouts', I hope you're talking about very short timeouts (on the order of 1 second), as we need the thread to stop almost immediately so that the user isn't sitting waiting for a long time after closing the connection.

I'm also having difficulty figuring out how to test on 2.2.2 because the emulator only seems to support 2.2.0 and my device only has 2.2.1. Is there any relatively straightforward way of getting a 2.2.2 device in the emulator?
May 23, 2011
#26 maurice....@commzgate.com
The only way I got around this was by using socket timeouts and a heartbeat mechanism.
May 23, 2011
#27 blahblah676
Ah, I see we already use setSoTimeout in our code from before we had the shutdownInput workaround (and I see I actually commented about it above). I use a timeout of 50ms so that there isn't a large delay for the user. I guess this is the best we can do, although I still have the problem that I have no way of testing in 2.2.2 as there doesn't appear to be any emulator for android 2.2.2.

Jun 10, 2011
#28 himanshu...@gmail.com
I tried blocking functions from DataInputStream (i.e read, readbyte ) they never throw IOException when server side TCP socket get closed. I tired on 2.2 froyo , 2.3 Nexus but had no success. 

Is there any work around or which version of android does not have this issue thanks

Jun 11, 2011
#29 blahblah676
himanshu: that is a different issue, and it works fine for me - I just tested on 2.2.1 and I do get an IOException when the server closes the socket (I tested by actually killing the server process). Are you sure it's not a bug in your code or a firewall issue?
Jun 15, 2011
#30 himanshu...@gmail.com
@blahblah
I do get the socket exception when kill or stop the server running on same port , but if i change the nic (wifi-network) to another network server side get closed but client side hang on blocking read function doest not get FIN i guess!!

thanks
Jun 16, 2011
#31 blahblah676
himanshu: I'm not sure exactly what you mean 'change the nic'. However I just tested our app again and just closing the socket on the server side does in fact generate an IOException on the Android device. Also see  issue 6144  which is specifically the bug you are talking about (marked 'Unreproducible', and it appears to be a bug in the user's code). I'm happy to look at your code if you want to post a fragment of it here.
Jun 16, 2011
#32 himanshu...@gmail.com
@31:
I mean my server is in c++ implementation on window and if you change wifi network to another netwrok available server side socket that is window server get closed but client side android app blocking on read or readbyte hang there does not get IOException.
Jun 16, 2011
#33 blahblah676
It sounds like you are basically breaking the network connection in the middle - when that happens there may be no RST or FIN packet send to the client, so it cannot possibly know that the connection is dead. This is the expected behaviour. You'll likely get an IOException if you get the client to transmit on the socket.
Jun 16, 2011
#35 himanshu...@gmail.com
@33:
Yep once server get closed if packet is sent further IOException will be raised but Question is after changing the network in the middle if server on the same port get closed must have got some notification from Netwrok layer why not client receive it ?.
 


Sep 14, 2011
#36 jessica....@gmail.com
I found the read functions in SocketInputStream only throw one IOException when wifi connection gets lost. If you have a subclass of java.io.InputStream to wrap SocketInputStream and use the implementation of InputStream.read(byte[], int, int) for your subclass, the java.io.InputStream.read(byte[], int, int) will never throw IOException. 

Does google aware this issue? Will be a fix for this?

Thanks, 
Sep 14, 2011
#37 jessewil...@google.com
@jessica.chen.mot yup, that looks like a problem. Please open a new issue to track that. We should be able to fix SocketException to always throw once it has failed.

By the way, you should ALWAYS override read(byte[], int, int) whenever you subclass InputStream. Otherwise you're going to end up reading one byte at a time which is extremely inefficient. I'll add a note to the InputStream docs to make that explicit.
Dec 27, 2011
#39 leew...@gmail.com
I still found this issue in Android 2.3.3 and Android 2.3.7. Steps,
  1. Setup local server in Android.
  2. Create client in the same device
  3. Connect to server and set setSoLinger(true, 0);
  4. Close the socket in client
  5. Server side can't get SocketException.
  
But, the simple workaround --shutdownInput() works fine.
Jan 29, 2012
Project Member #40 e...@google.com
 Issue 24318  has been merged into this issue.
Feb 27, 2012
Project Member #41 e...@google.com
 Issue 26066  has been merged into this issue.
Feb 27, 2012
Project Member #42 e...@google.com
 Issue 26098  has been merged into this issue.
Mar 2, 2012
Project Member #43 e...@google.com
 Issue 26281  has been merged into this issue.
Dec 3, 2012
Project Member #44 e...@google.com
(No comment was entered for this change.)
Labels: Restrict-AddIssueComment-Commit
Sign in to add a comment

Powered by Google Project Hosting