Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EMFILE (Too many open files) error while connecting to LocalServerSocket?

Tags:

android

inode

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

like image 999
kakopappa Avatar asked May 09 '14 08:05

kakopappa


1 Answers

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();
            }
        }
    }
like image 169
exloong Avatar answered Oct 08 '22 22:10

exloong