Java - "нет места в буфере" причина ошибки сокета? - PullRequest
0 голосов
/ 14 декабря 2010

Я пишу сетевую программу на Java. Я использую объекты ServerSocket и Socket для отправки и получения сообщений с использованием TCP. Моя программа работает нормально, если выполняется в течение короткого времени, однако, если я запускаю ее в течение более длительного времени, я получаю следующую ошибку:

java.net.SocketException: No buffer space available (maximum connections reached?): connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(Unknown Source)
at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)

Я подумал, что это может быть из-за того, что я не закрываю все сокеты, но я изменил свой код: у меня есть один класс, который я создаю, когда хочу новый сокет, и добавил метод finalize для его закрытия. У меня также есть метод finalize для закрытия ServerSocket, поэтому я не знаю, в чем проблема.

Кроме того, после того, как я получаю ошибку, если я сразу же снова запускаю программу, она сталкивается с проблемой быстрее, чем раньше. Затем, если я подожду некоторое время и запустлю его, он вернется к исходному времени.

Я действительно не могу решить проблему, и я пытался понять это целую вечность. Кто-нибудь знает, в чем проблема?

Заранее спасибо!

UPDATE:

Итак, я выяснил, откуда возникла ошибка, и это действительно странно. У меня есть следующий код, который вызывает проблему:

try {
        sock = new Socket(InetAddress.getByName(ipaddr), port);
        sock.close();

        // os = sock.getOutputStream();
        // byte[] arr = s.getBytes();
        // os.write(arr);
        // os.close();

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            sock.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Как видите, код должен открыть сокет и записать в него. Однако даже когда весь функциональный код закомментирован, как указано выше, поэтому сокет просто открывается, а затем сразу закрывается, я все равно получаю ошибку «нет места в буфере».

Я действительно не могу понять, почему это так. Программа является многопоточной, и каждый поток периодически создает объекты с помощью вышеуказанного метода и вызывает его. Когда строки для создания и закрытия сокета удалены, я больше не получаю сообщение об ошибке, но когда они есть, даже если сокет открывается и сразу закрывается, я получаю сообщение об ошибке.

Кто-нибудь знает, почему это происходит?

Большое спасибо.

Ответы [ 2 ]

5 голосов
/ 14 декабря 2010

У меня есть один класс, который я создаю, когда хочу новый сокет, и добавил метод finalize , чтобы закрыть его. У меня также есть метод finalize для закрытия ServerSocket, поэтому я не знаю, в чем проблема.

Bzzt. Стоп. Проверьте. Финализаторы являются недетерминированными при запуске (за исключением некоторого времени после того, как объект больше не доступен, хотя, возможно, даже если приложение Java завершает работу!) - см. Уничтожение и финализация . Убедитесь, что вы используете явный контракт, такой как Closable, и вызываете его насквозь (не ждите, когда появится GC!).

Эта проблема наиболее показательна для «утечки» внешних ресурсов - так как GC заботится главным образом о памяти и о нехватке памяти, если есть небольшое давление и / или GC не агрессивен, очень легко выйти из внешнего Сначала ресурсы, потому что финализаторы еще не запущены (пока). В общем, финализатор - это сеть безопасности (которая не всегда работает), но не замена для других форм управления внешними ресурсами.

По ссылке выше:

Java не дает никаких гарантий относительно того, когда будет происходить сборка мусора или в каком порядке будут собираться объекты. Следовательно, Java не может дать никаких гарантий относительно того, когда (или даже будет ли) вызываться финализатор , в каком порядке будут вызываться финализаторы или какой поток будет выполнять финализаторы.

Удачного кодирования.

Редактировать: См. Этот связанный вопрос: Зачем вам когда-нибудь реализовать finalize ()? . Мне нравится второй ответ от Стива Джессопа.

2 голосов
/ 14 декабря 2010

Не используйте finalize для закрытия ресурсов.Это не будет работать надежно.

(Существует вероятность того, что объекты ресурсов не будут завершены достаточно скоро, и у вас закончатся ресурсы. Вы не можете контролировать, когда запускаются финализаторы, и возможно, что они никогда не получатзапустить.)

Что вы должны делать, это что-то вроде этого:

    Resource resource = // allocate resource
    try {
        // Use the resource ...
    } 
    catch (SomeException ...) {
        // Deal with errors from using the resource
    } 
    finally {
        try {
            resource.close()}
        }
        catch (SomeException ...) {
            // Deal with errors from closing the resource
        }
    }
...