java.net.ServerSocket.accept () не возвращается на Android - PullRequest
7 голосов
/ 01 сентября 2011

Я пытаюсь подключиться к telnet без рутированного Droid. У меня активировано разрешение INTERNET, мое устройство подключено к той же сети, что и моя коробка Mac OS X через WiFi, и я могу пропинговать открытый порт.

В первоначальных экспериментах я заставлял его работать на рутованном тестовом устройстве, но обработчики сокетов выполнялись на UI Thread, а не в отдельном потоке. Теперь, когда у меня есть сетевые модули в отдельном потоке, я не могу получить ServerSocket.accept () для возврата. Он работает на версии Android от Google (vanilla), но не на Samsung или Sony-Ericsson.

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

Вот ссылка на репо моего кода с Google-кодом: Хранилище Google-кода

Я запускаю ServerScoket.accept () в отдельном потоке и запускаю потоковые процессоры также в другом потоке. Комментарии к моему дизайну (то есть я должен использовать Handler s или AsyncTasks) крайне приветствуются. Прямо сейчас, чтобы Toast сообщения, полученные через telnet, я использую Обработчик с петлителем, полученным через Context.

Вот что я получаю, когда запускаю netstat -n в оболочке adb на нерабочих устройствах:

~$ adb shell netstat -n
Proto Recv-Q Send-Q Local Address          Foreign Address        State
tcp        0      0 127.0.0.1:7777         0.0.0.0:*              LISTEN
tcp        0      0 127.0.0.1:7203         0.0.0.0:*              LISTEN
tcp        0      0 127.0.0.1:47609        127.0.0.1:7777         ESTABLISHED
tcp        0      0 127.0.0.1:7777         127.0.0.1:47609        ESTABLISHED
tcp        0      0 127.0.0.1:47610        127.0.0.1:7777         ESTABLISHED
tcp        0      0 127.0.0.1:7777         127.0.0.1:47610        ESTABLISHED

Разница в том, что на работающих устройствах они перечисляют IP с моим открытым портом в состоянии LISTEN.

ОБНОВЛЕНИЕ : Установив <uses-permission android:name="INTERNET"/> в моем android_manifest, я попытался изменить номер порта на 689. Это не сработало; Я получил BindException, сказав, что мне, возможно, не хватает разрешения ИНТЕРНЕТ. Итак, я изменил его на 1989 и вернулся к тому, что все работало до accept (). Я предполагаю, что это потому, что я запустил его на телефоне без полномочий root, и у меня нет доступа к портам 1024 и ниже.

ОБНОВЛЕНИЕ : я запустил очень похожую программу на своем Mac, и она работала нормально, когда я пытался подключиться к своему Mac с помощью telnet, используя назначенный мне IP-адрес. Это не сработало, когда я попробовал телнетить с другого Mac, но, похоже, не подключилось; соединение будет прервано. Это действительно работало по специальной сети, все же. Я все еще должен попробовать это, используя дроида, но я обновлю это как можно скорее.

ОБНОВЛЕНИЕ : мне удалось заставить приложение работать на 3 отдельных дроидах под управлением Vanilla (Android выпущен Google). Он работал на Nexus, Apanda A60 (мое первое устройство; adb по какой-то причине перестал его обнаруживать) и на заказном планшете без бренда. Тем не менее, поскольку я уже предложил довольно большую награду, я планирую довести это до конца.

Как уже говорилось ранее, мое приложение работает с версиями Android для Vanilla, но не с модифицированными версиями. Три телефона, которые не смогли его запустить, были моделями среднего класса; 2 Samsung GT-i5503 с и Sony-Ericcson E16i.

Ответы [ 3 ]

1 голос
/ 05 сентября 2011

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

Я добавил это к TelnetServer.setupServerSocket(), чтобы подтвердить некоторую информацию:

Log.i("TelnetServer", "ServerSocket Address: " + this.server.getLocalSocketAddress());
try {
    Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
    while (en.hasMoreElements()) {
        NetworkInterface intf = en.nextElement();
            for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                InetAddress inetAddress = enumIpAddr.nextElement();
                Log.i("TelnetServer", "Listen On: " + inetAddress.getHostAddress());
            }
        }
} catch (SocketException ex) {
    Log.e("TelnetServer", ex.toString(), ex);
}

Это напечатает все адресаваша служба прослушивает (если она прослушивает 0.0.0.0/0.0.0.0:xxx (печатается после ServerSocket Address:)).

Вы должны запустить emulator с параметром -tcpdump <file>, а также предоставитьэтот.Это подтвердит любую попытку соединения.Я догадываюсь, что ваш клиент не может получить доступ к серверу, поэтому сервер не получает соединение, а не проблема с кодом.

Пожалуйста, предоставьте файл tcpdump, ваш IP-адрес (изклиента) и вывод logcat (включая операторы ServerSocket Address и Listen On) для дальнейшего анализа.

1 голос
/ 01 сентября 2011

Посмотрите, показывает ли netstat -n из оболочки adb что-либо, действительно прослушивающее порт, который вы выбрали в тот момент, когда accept () не возвращает.

Также следует понимать, что когда вы не работаете от имени пользователя root, вы можете связывать только непривилегированные порты, из которых порт telnet по умолчанию не является примером. Ваш код проверяет, что bind () был успешным?

UPDATE:

Так как код работает на нескольких устройствах (где netstat -n предположительно перечислит сокет), невозможность перечислить его на соответствующем устройстве, вероятно, должна оставаться в центре внимания. Методы Java ServerSocket зависят от фабрики сокетов, которая может быть переопределена, чтобы позволить вам делать различные вызовы socket (), bind () и listen (), определяя более полные детали, поэтому может иметь смысл попробовать ваш код таким способом. Существует еще один случай, когда попытка устройства поддержать ipv6, похоже, вызывает у кого-то аналогичные проблемы, и, по крайней мере, на других платформах java создание сокета на более низком уровне для указания ipv4 кажется многообещающим ответом.

0 голосов
/ 11 сентября 2011

Я понимаю, что вы пробовали большинство вещей в том, что вы находитесь всего в нескольких шагах от правильной настройки на двух конкретных устройствах.

Просто мысль. Если не указать, то почему бы не использовать Muti-casting для регистрации и обнаружения услуг в локальных сетях.

Это реализация Java JmDNS

и это его Android-демо

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

...