连接到LocalServerSocket时EMFILE(打开文件太多)错误?

kak*_*ppa 5 android inode

我的应用很简单.客户端将连接到LocalServerSocket(Unix域套接字)并发送一些数据并断开连接.如果此过程重复超过1024次,则服务器java.io.IOException: socket failed: EMFILE (Too many open files)在接受新客户端时抛出.

我已经在http://speedy.sh/NBSjr/SocketIssue.zip上传了我的演示代码

您可以在代码中看到客户端在与服务器建立另一个连接之前关闭了连接.在logcat中,您可以看到服务器中的FileDescriptor计数正在增加,并且在第1023次客户端连接时崩溃.

我该如何解决这个问题?请指教

我在运行Android 4.3的三星S4上尝试过它.它似乎是重用文件描述符,我的演示应用程序可以运行几个小时!

更新于2014-05-19

如果您没有运行Android 4.4.2的设备,您可以在运行Android 4.4.2的仿真器上试用此代码

exl*_*ong 1

我花了一段时间来运行你的代码,并填充所有的 try-catch 块,e.printStack();看看是否有一些异常被忽略,但运气不好,我无法得到相同的结果IOException,它已经运行了 1 个多小时,没有任何异常。例外。

我有一个问题可能会有所帮助,那就是我找不到任何要计数的代码FileDescriptor,也许您没有上传正确版本的代码,或者,您将数字误认为log 05-18 05:18:50.409: V/SocketCmdServer(636): Incoming client fd:FileDescriptor[35]是计数FileDescriptor,我读了toString()of的源码FileDescriptor,number不是计数器而是fd类型。

/**
* 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 + "]";
}
Run Code Online (Sandbox Code Playgroud)

任何在 Linux 上运行的 java 虚拟机都可能有最大套接字连接数,因为 Linux 将套接字连接视为文件,您可以通过这些 linux cmds 查看最大数量:

cat /proc/sys/fs/file-max
Run Code Online (Sandbox Code Playgroud)

(PS:您可能需要一个 busybox 才能在 Android 中获取完整的 linux cmd)

不建议修改最大文件数。

最重要的是,我有如下建议:
1)尽量避免达到系统设置的套接字连接的最大数量限制
2)填充所有的try-catch块以打印跟踪堆栈以查看是否成功关闭套接字

 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();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)