【问题标题】:EMFILE (Too many open files) error while connecting to LocalServerSocket?连接到 LocalServerSocket 时出现 EMFILE(打开的文件过多)错误?
【发布时间】:2014-06-26 21:52:06
【问题描述】:

我的应用程序非常简单。客户端将连接到 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 年 5 月 19 日更新

如果您没有运行 Android 4.4.2 的设备,您可以在运行 Android 4.4.2 的模拟器上尝试此代码

【问题讨论】:

  • 阅读主题你建议1024个同时连接。你责怪 LocalServer,也许你不得不责怪 FileDescriptor。你需要那个描述符做什么?您在服务器中只有一个 closeClient() 调用,永远不会被调用。由于服务器在收到并返回一条消息后不处理客户端,因此您也可以让服务器关闭客户端。将 closeClient() 放在 oos.flush() 之后的 try 块中。也许这会关闭文件描述符。
  • 我有一台服务器。一个或多个客户端可以连接到该服务器。客户端将连接发送一些数据并断开连接。如果这种情况发生超过 1024 次,则抛出 java.io.IOException: socket failed: EMFILE (Too many open files)
  • 是的,我明白这一点,正如您在我的评论中看到的那样。但是您是否实施了我的建议并尝试过?请对建议做出反应。
  • 感谢您的建议。我在 oos.flush() 之后移动了代码。没用

标签: android inode


【解决方案1】:

我需要一些时间来运行你的代码,并用e.printStack(); 填充所有的try-catch 块,看看是否有一些异常被忽略,但是没有运气,我不能得到相同的IOException,它已运行超过 1 小时,无异常。

我有一个问题可能会有所帮助,那就是我找不到任何代码来计算 FileDescriptor ,也许你没有上传正确的代码版本,或者你弄错了 @987654325 中的数字@对于FileDescriptor的计数,我看了FileDescriptortoString()的源码,这个数字不是计数器而是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 + "]";
}

Linux 上运行的任何 java vm 都可能有最大套接字连接数,因为 linux 将套接字连接作为文件,您可以通过这些 linux cmds 看到最大连接数:

cat /proc/sys/fs/file-max

(PS:你可能需要一个busybox才能在android中获取完整的linux cmds)

不建议修改最大文件数。

首先,我的建议如下:
1) 尽量避免达到系统设置的最大套接字连接数限制
2) 填满你们所有的try-catch块来打印track stack,看看你是否成功关闭了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();
            }
        }
    }

【讨论】:

  • 感谢您花时间看这个。我尝试使用您建议的 try/catch 方法。关闭套接字/流时我没有看到任何错误。我也可以在 Android 4.4 模拟器上重现此问题。如果您可以使用 Android 4.4 创建模拟器,您可以在 LogCat 中看到。我在这里上传了我的 LogCat 快照sharesend.com/cwbpf0bn
猜你喜欢
  • 2016-02-08
  • 1970-01-01
  • 2018-04-01
  • 1970-01-01
  • 2012-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多