6

My app is pretty simple. Client will connect to a LocalServerSocket (Unix Domain Socket) and send some data and disconnect. If this process repeat over 1024 times, Server throws java.io.IOException: socket failed: EMFILE (Too many open files) when accepting new client.

I have uploaded my demo code here http://speedy.sh/NBSjr/SocketIssue.zip

You can see in the code that client closes the connection made before making another connection to the server. In the logcat you can see FileDescriptor count is increasing in the server and crashes when client connects on 1023rd time.

How do I fix this problem ? Please advice

I tried it on Samsung S4 running Android 4.3. It seems it is reusing file descriptors and my demo app can run for hours!

Updated on 2014-05-19

If you do not have a device running Android 4.4.2 You can try this code on an Emulator running Android 4.4.2

kakopappa
  • 5,023
  • 5
  • 54
  • 73
  • Reading the subject you suggest 1024 simultanuous connections. You blame LocalServer where maybe you have to blame FileDescriptor. For what do you need that descriptor? You have only one closeClient() call in the server which will never be called. As the server does not handle a client after one message received and returned you could aswell let the server close the client. Put closeClient() in the try block after oos.flush(). Maybe that closes the file descriptor. – greenapps May 09 '14 at 09:06
  • I have a one Server. One or more clients can connect to that server. A client will connect send some data and disconnect. if this happens more than 1024 times it Throws java.io.IOException: socket failed: EMFILE (Too many open files) – kakopappa May 09 '14 at 09:29
  • Yes I understood that as you can read in my comment. But did you implement my suggestion and tried it? Please react on suggestions. – greenapps May 09 '14 at 09:39
  • Thanks for your suggestion. I moved the code after oos.flush(). didn't work – kakopappa May 09 '14 at 10:48

1 Answers1

1

I take a while to run your code, and fill all of the try-catch blocks with e.printStack(); to see whether there are some exceptions ignored, but no luck, I can't get the same IOException, it has run for more than 1 hour with no Exception.

I have one question that may do some help, that is I can't find any code to count FileDescriptor , maybe you didn't upload the right version of the code, or, you mistook the number in log 05-18 05:18:50.409: V/SocketCmdServer(636): Incoming client fd:FileDescriptor[35] for the count of FileDescriptor, I read the source code of toString() of FileDescriptor, the number is not a counter but a fd type.

/**
* The Unix file descriptor backing this FileDescriptor.
* A value of -1 indicates that this FileDescriptor is invalid.
*/
private int descriptor = -1;

@Override public String toString() {
    return "FileDescriptor[" + descriptor + "]";
}

any java vms run on Linux may have the max socket connetion numbers, beacuse linux take socket connection as a file, you can see the max number via these linux cmds:

cat /proc/sys/fs/file-max

(PS: you may need a busybox to get full linux cmds in android)

and it is not recommanded to modify the max file number.

above all, I've suggestions as below:
1) try to avoid reach the max number limit of socket connections set by system
2) fill all of you try-catch block to print the track stacks to see whether you succeefully close the socket

 private void connectToServer() {
        LocalSocket client = null;
        ObjectOutputStream oos = null;
        ObjectInputStream ois  = null;
        try {
            client = new LocalSocket();

            Log.v(TAG, "connectToServer # Connect to the server");
            client.connect(new LocalSocketAddress(SOCKER_SERVER_NAME));

            Log.v(TAG, "connectToServer # Send the command");
            oos = new ObjectOutputStream(client.getOutputStream());
            oos.writeObject(new String("Hello"));
            oos.flush();

            ois = new ObjectInputStream(client.getInputStream());
            Object obj = ois.readObject();

            Log.v(TAG, "connectToServer # Response is received");
        }
        catch (Exception e) {
                Log.e(TAG, "connectToServer # Error:..", e);
        }
        finally {

            // each close() method should be wrapped in seperated try-catch block
            // or 1 or 2 close() method will be skipped
            try {
                if (oos != null) {
                    oos.close();
                    oos = null;
                }
                if (ois != null) {
                    ois.close();
                    ois = null;
                }

                if(client != null) {
                    client.close();
                    client = null;
                }
            }
            catch (IOException e) { 
                e.printStackTrace();
            }
        }
    }
exloong
  • 441
  • 3
  • 6
  • Thank you for taking time to look at this. I tried using try/catch methods you have suggested. I did not see any errors while closing the socket/streams. I can reproduce this issue on Android 4.4 emulator as well. If you can create a emulator with Android 4.4 you can see in LogCat. I have uploaded a snap of my LogCat here http://sharesend.com/cwbpf0bn – kakopappa May 19 '14 at 04:10