«BindException: адрес уже используется» после перезапуска приложения - PullRequest
0 голосов
/ 04 октября 2011

При перезапуске приложения я получил исключение BindException.Он действует как сервер, ожидающий сообщений удаленного управления.ServerSocket работает в фоновом потоке (AsyncTask).После перезапуска моего приложения я всегда получаю исключение, упомянутое выше.Мне нужно ждать около 10 минут, пока он не сможет снова привязаться к порту, чтобы прослушать.

Я пробовал разные порты (все> 50000), поэтому я уверен, что нет другого приложения, блокирующего мой порт.Я пытался быть осторожным с закрытием сокета и пытался использовать опцию SO_REUSEADDR.Также я уверен, что во время выполнения открыто только одно соединение, так как я регистрировал каждое гнездо.

Так что я думаю, что соединение не закрыто должным образом.Я читал о привычке сокетов не закрываться мгновенно.Но я не могу ждать, как 10 минут при каждом перезапуске приложения, и я не нашел способ сократить или убить это время.

У вас есть какие-либо идеи?

Исключение:

10-04 16:39:22.526: WARN/System.err(4974): java.net.BindException: Address already in use
10-04 16:39:22.526: WARN/System.err(4974):     at org.apache.harmony.luni.platform.OSNetworkSystem.bind(Native Method)
10-04 16:39:22.526: WARN/System.err(4974):     at dalvik.system.BlockGuard$WrappedNetworkSystem.bind(BlockGuard.java:275)
10-04 16:39:22.526: WARN/System.err(4974):     at org.apache.harmony.luni.net.PlainSocketImpl.bind(PlainSocketImpl.java:165)
10-04 16:39:22.526: WARN/System.err(4974):     at java.net.ServerSocket.<init>(ServerSocket.java:123)
10-04 16:39:22.526: WARN/System.err(4974):     at java.net.ServerSocket.<init>(ServerSocket.java:74)
10-04 16:39:22.526: WARN/System.err(4974):     at com.*******.remote.RemoteHandlerListener$1.doInBackground(RemoteHandlerListener.java:114)

Код:

ServerSocket server;
try {
    server = new ServerSocket();
    server.setReuseAddress(true);
    server.bind(new InetSocketAddress(serverport));
} catch (IOException e) {
    e.printStackTrace();
    return null;
}

while (true) {
    BufferedReader inStream = null;
    Socket client = null;
    try {
        client = server.accept();
        inStream = new BufferedReader(new InputStreamReader( client.getInputStream()));
        // read from stream
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (inStream != null) {
            try {
                inStream.close();
            } catch (IOException e) { }
        }
        if (client != null) {
            try {
                client.close();
            } catch (IOException e) { }
        }
    }
}
try {
    server.close();
} catch (IOException e) { }

Исключение выдается в операторе server.bind.

РЕДАКТИРОВАТЬ: причина проблемы: поток не завершит себятак как принять вызов блокируется.Программа не завершилась полностью, и сокет не был освобожден.

Решение: Установите SO_TIMEOUT на сокет и проверьте isCancelled в цикле while ().Таким образом, поток завершится, если вы вызовете на нем метод cancel ().

Ответы [ 3 ]

0 голосов
/ 04 октября 2011

Согласен. Обычно это означает, что при перезапуске не удалось правильно завершить процесс сервера. Каким-то образом он все еще работает, и поэтому порт все еще заблокирован.

Ожидание в течение 10 минут довольно долго. Просто проверьте (если возможно), завершился ли ранее запущенный процесс Java.

0 голосов
/ 04 октября 2011

Если вы еще этого не сделали, вам следует изучить материал для разработчиков Android на Activity Lifecycles .В этой статье говорится, что операционная система Android не дает абсолютно никаких гарантий относительно того, когда приложение будет убито, за исключением того, что это может произойти в любое время, и поэтому они предоставляют onPause, onResume, onRestart и т. Д. Вы не можетеВы когда-нибудь гарантируете, что ваше приложение всегда будет полностью умирать, но вы можете выполнить собственную очистку, и я бы порекомендовал убить ваш поток и закрыть сокет (или другое управление) внутри onPause.

Кроме того, когдаиспользуя Java-сокеты (будь то Android или нет), никогда не рекомендуется, чтобы завершение программы было действием, которое закрывает ваши сокеты.Вы должны почти всегда закрывать их самостоятельно в какой-то зоне очистки.Особенно при работе с потоками.

Обновление: вы сказали, что наносите ответный удар и затем перезапускаетесь.Это не называет Дестрой.onDestroy вызывается только в том случае, если ОС требуется память и полностью убивает ваше приложение (эквивалент убийства в диспетчере задач)

0 голосов
/ 04 октября 2011

Попробуйте напечатать трассировку стека всех обнаруженных исключений.Это, вероятно, очень поможет.Возможно, что-то не так в вашем коде, который вы опубликовали.Вы создаете блоки try-catch, не обрабатывая исключение.Вы даже не знаете, есть ли такие.


Обновление: следующий шаг - убедиться, что ваше приложение действительно остановлено.С первого взгляда на ваш код вы никогда не выходите из бесконечного цикла приема клиентов.Попытайтесь это исправить и добавьте оператор печати после закрытия сокета сервера:

try {
    server.close();
    System.out.println("Server successfully stopped.");
} catch (IOException e) { }

Убедитесь, что вы нашли это в выходных данных вашего приложения.Вы можете принудительно завершить работу приложения (и сокета сервера), используя:

System.exit(0);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...