Java RMI не закрывает сокет после истечения срока аренды - PullRequest
1 голос
/ 22 октября 2008

У моего приложения с поддержкой RMI, похоже, утечка сокетов. У меня есть приложение Java, предоставляющее сервис через RMI. Он использует реализацию Java SE 1.6 RMI, работающую в Linux. Проблема, которую я наблюдаю, состоит в том, что, если клиент получает ссылку на мой удаленный объект, используя реестр, а затем соединение прерывается внезапно (потеря питания, отключение кабеля и т. Д.), Сервер сохраняет сокет открытым. Я ожидаю, что реализация RMI будет очищена после истечения срока аренды клиента, но этого не происходит. На сервере метод unreferenced() моего удаленного объекта вызывается по истечении срока аренды, но сокет остается видимым в netstat в состоянии «ESTABLISHED» в течение неопределенного времени.

Поскольку мы не можем принудить клиентов к каким-либо особым действиям, через несколько дней мы достигаем предела по умолчанию 1024 в нашем дистрибутиве Linux для дескрипторов открытых файлов, из-за чего сервер не может открыть какие-либо новые сокеты или файлы. Я думал о TCP keepalive, но поскольку RMI абстрагируется от сетевого уровня, у меня нет доступа к фактическому сокету сервера после того, как соединение установлено.

Есть ли способ заставить уровень RMI очистить сокеты, связанные с клиентскими соединениями с истекшим сроком аренды?

Обновление: Решение, которое я использовал, похоже на выбранный ответ, но использует другой подход. Я использовал настраиваемую фабрику сокетов, а затем обернул экземпляр ServerSocket, возвращаемый createServerSocket (), в прозрачную оболочку, которая пропускала все методы, кроме accept (). В методе accpet keepalive активируются до возвращения сокета.

public class KeepaliveSocketWrapper extends ServerSocket
{
    private ServerSocket _delegate = null;
    public KeepaliveSocketWrapper(ServerSocket delegate)
    {
        this._delegate = delegate;
    }

    public Socket accept() throws IOException
    {
        Socket s = _delegate.accept();
        s.setKeepAlive(true);
        return s;
    }
    .
    .
    .
}

1 Ответ

0 голосов
/ 23 октября 2008
public class MySocketFactorySettingKeepAlive ... {
  // overwrite createSocket methods, call super.createSocket, add keepAlive
}

Socket.setSocketImplFactory(youFactoryDemandingKeepAlive);

, а затем просто используйте RMI.

Хитрость, если я правильно помню, заключается в том, чтобы установить фабрику до того, как система откроет первый сокет - Java запрещает перезаписывать фабрику; в худшем случае используйте отражение, чтобы перезаписать его :))) (шучу; было бы взломать)

Кроме того, вам может потребоваться разрешить определенную операцию в SecurityManager.

...