DatagramChannel.close () сохраняет порт открытым в Windows

m реализует процесс Discover, который:

Откройте сокет UDP для прослушивания широковещательного ответа на данный портОтправить несколько запросов (и ожидать ответа позже)Закройте сокет UDP через определенный промежуток времени

Первый звонок работает. Но другой вызов получает ошибку связывания. Адрес уже используется: bindI '

Я запустил Windows 7. Я провел несколько тестов и обнаружил, что после channel.close (); Netstat все еще дает:

netstat -a -b -sp udp | grep 55224

UDP 0.0.0.0:55224:

Так что порт udp все еще открыт на уровне ОС

Я искал в Интернете, и это может быть утечка на уровне ОС:Некоторые вопросы Java Datagram Socket

Я провел 2 теста, один с использованием канала NIO, а другой без (из теста, найденного в Интернете). Я воспроизвожу свою ошибку с версией NIO, но она работает, если я не использую NIO.

Я любой могу указать мне, как я могу сделать это работает с NIO. Целевой платформой является Android, где я надеваюt want всегда слушать трансляцию, но только в течение повторяющегося периода времени.

Тестовая розетка
    public void testConnectCloseWithSocket() {
    long tCumulative = 0;
    int errAt = -1;
    System.out.println("start...");
    for (int i = 0; i < 4000; i++) {
        try {
            errAt = i;
            DatagramSocket result = new DatagramSocket(null);
            result.bind(new InetSocketAddress(InetAddress.getLocalHost(), 9005));
            result.close();

            //success at last
            tCumulative = 0;

        } catch (Exception e) {
            System.out.println("Error (at="+errAt+") (waited="+tCumulative+"ms): " + e.getMessage());

            tCumulative+=50;
            try {
                Thread.sleep(50);
            } catch (InterruptedException e1) {


            }
            i--;
        }
    }
    System.out.println("end...");

}
РЕЗУЛЬТАТ РАССЕТА <

начало ... Ошибка (при = 1319) (ожидание = 0 мс): адрес уже используется: невозможно связать

Ошибка (при = 1438) (ожидание = 0 мс): адрес уже используется: невозможно связать

Ошибка (при = 1587) (ожидание = 0 мс): адрес уже используется: невозможно связать

Ошибка (при = 1740) (ожидание = 0 мс): адрес уже используется: невозможно связать

конец...

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

ТЕСТ С КАНАЛОМ
    public void testConnectCloseWithChannel() {
    long tCumulative = 0;
    int errAt = -1;
    System.out.println("start...");
    for (int i = 0; i < 4000; i++) {
        try {
            errAt = i;
            Selector selector = Selector.open();
            DatagramChannel channel = DatagramChannel.open();
            channel.configureBlocking(true);
            channel.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 9005));
            SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
            clientKey.cancel();
            channel.close();

            //success at last
            tCumulative = 0;

        } catch (Exception e) {
            System.out.println("Error (at="+errAt+") (waited="+tCumulative+"ms): " + e.getMessage());

            tCumulative+=50;
            try {
                Thread.sleep(tCumulative);
            } catch (InterruptedException e1) {


            }
            i--;
        }
    }
    System.out.println("end...");

}

ПРИМЕЧАНИЕ: если канал.register прокомментирован, тестовые работы

РЕЗУЛЬТАТ С КАНАЛОМ

начало ... Ошибка (при = 0) (ожидание = 0 мс): ноль Ошибка (при = 0) (ожидание = 50 мс): адрес уже используется: bind

Ошибка (при = 0) (ожидание = 100 мс): адрес уже используется: bind

Ошибка (при = 0) (ожидание = 150 мс): адрес уже используется: bind ...

Спасибо за любую помощь

Ответы на вопрос(2)

если канал зарегистрирован с помощью селектора. Это задокументировано где-то в лесу селекторов, AbstractSelector, SelectorSpi, SelectableChannel, AbstractSelectableChannel, где я никогда не могу найти его, когда мне это нужно. Если ты'Находясь в цикле выбора и потоке, когда вы закрываете канал, вы можете сделать это немедленно, вызвав selectNow ().

но сокет закрывается должным образом ..., что Oki для моих нужд

Нет, если тыУ вас есть ошибки, ваш канал НЕ закрыт должным образом.

Ты должен сделатьclose вfinally пункт вашегоtry блок.

Selector selector = Selector.open();
try
{
  DatagramChannel channel = DatagramChannel.open();

  try
  {
    channel.configureBlocking(true);
    channel.socket().bind(
      new InetSocketAddress(InetAddress.getLocalHost(), 9005)
    );
    SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
    clientKey.cancel();
  }
  finally
  {
    channel.close();
  }
}
finally
{
  selector.close( )
}
 David Gagnon19 окт. 2012 г., 19:26
Спасибо за примечание и работая над вашим кодом, я заметил, что я неt закрытие селектора. Закрыв его все работает :-) Спасибо!
 user20742124 окт. 2012 г., 06:33
@DavidGagnon That 'из-за проблемы, поднятой в моем ответе.

Ваш ответ на вопрос