Многоадресная рассылка не работает для Android 2.0.1 (сейчас на DROID) или я что-то упускаю?
Вопрос
Этот код отлично работает в Ubuntu, Windows и Mac OS X.Он также отлично работает с Nexus One под управлением Android 2.1.1.
Я начинаю отправлять и прослушивать многоадресные датаграммы, и все компьютеры и Nexus One прекрасно видят друг друга.Затем я запустите тот же код на Droid (прошивка 2.0.1) и все получат пакеты, отправленные дроидом, но дроид будет слушать только свои собственные пакеты.
Это run()
метод потока, который постоянно прослушивает группу многоадресной рассылки на предмет входящих пакетов, отправленных в эту группу.
Я провожу тесты в локальной сети, где в маршрутизаторе включена поддержка многоадресной рассылки.Моя цель — обеспечить, чтобы устройства встречали друг друга при подключении к сети путем широковещательной передачи пакетов в группу многоадресной рассылки.
public void run() {
byte[] buffer = new byte[65535];
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
try {
MulticastSocket ms = new MulticastSocket(_port);
ms.setNetworkInterface(_ni); //non loopback network interface passed
ms.joinGroup(_ia); //the multicast address, currently 224.0.1.16
Log.v(TAG,"Joined Group " + _ia);
while (true) {
ms.receive(dp);
String s = new String(dp.getData(),0,dp.getLength());
Log.v(TAG,"Received Package on "+ _ni.getName() +": " + s);
Message m = new Message();
Bundle b = new Bundle();
b.putString("event", "Listener ("+_ni.getName()+"): \"" + s + "\"");
m.setData(b);
dispatchMessage(m); //send to ui thread
}
} catch (SocketException se) {
System.err.println(se);
} catch (IOException ie) {
System.err.println(ie);
}
}
Это код, который отправляет многоадресную датаграмму из каждого доступного сетевого интерфейса (это не интерфейс обратной связи).
public void sendPing() {
MulticastSocket ms = null;
try {
ms = new MulticastSocket(_port);
ms.setTimeToLive(TTL_GLOBAL);
List<NetworkInterface> interfaces = getMulticastNonLoopbackNetworkInterfaces();
for (NetworkInterface iface : interfaces) {
//skip loopback
if (iface.getName().equals("lo"))
continue;
ms.setNetworkInterface(iface);
_buffer = ("FW-"+ _name +" PING ("+iface.getName()+":"+iface.getInetAddresses().nextElement()+")").getBytes();
DatagramPacket dp = new DatagramPacket(_buffer, _buffer.length,_ia,_port);
ms.send(dp);
Log.v(TAG,"Announcer: Sent packet - " + new String(_buffer) + " from " + iface.getDisplayName());
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e2) {
e2.printStackTrace();
}
}
Обновление (2 апреля 2010 г.)Я нашел способ заставить сетевой интерфейс Droid обмениваться данными с помощью многоадресной рассылки: WifiManager.MulticastLock.
MulticastLock _wifiMulticastLock = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE)).createMulticastLock("multicastLockNameHere");
_wifiMulticastLock.acquire();
Потом, когда ты закончишь...
if (_wifiMulticastLock != null && _wifiMulticastLock.isHeld())
_wifiMulticastLock.release();
После того, как я это сделал, Droid начал отправлять и получать датаграммы UDP в группе многоадресной рассылки.
Обновление 6 июля 2010 г.
По запросу, вот мой текущий код, следующий метод существует в абстрактном классе, который можно использовать как для широковещательных, так и для многоадресных приемников.
public void run() {
onInit();
try {
byte[] data = new byte[65535];
while (isProcessing()) {
try {
DatagramPacket receivedDatagram = new DatagramPacket(data, data.length);
_socket.receive(receivedDatagram);
onDatagramReceived(receivedDatagram);
data = new byte[65535]; // This pattern is for saving memory allocation.
} catch (InterruptedIOException e) {
if (!isProcessing())
break;
}
} // while
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
} finally {
onStop();
_socket.close();
_socket.disconnect();
}
}
Ваши расширяющие классы должны реализовывать onInit()
и onDatagramReceived()
Для Многоадресная рассылка получатель, onInit()
выглядит что-то так:
_socket = new MulticastSocket(PORT_MULTICAST);
InetAddress groupAddress = InetAddress.getByAddress(MULTICAST_GROUP_ADDRESS);
InetAddress groupInetAddress = FrostWireUtils.fastResolveAddress(groupAddress); //reflection hack to not resolve ips
try {
_socket.setSoTimeout(500);
_socket.setTimeToLive(MULTICAST_TTL_GLOBAL);
_socket.setReuseAddress(true);
_socket.setNetworkInterface(
WifiUtils.getWifiNetworkInterface());
_socket.joinGroup(groupInetAddress);
WifiUtils.lockMulticast();
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
Решение
Я реализовал еще один тест, на этот раз с использованием UDP. Транслировать.Оно работает.
Заключение: Насколько мне известно, телефоны Motorola Droid на прошивке 2.0.1 не поддерживают многоадресную рассылку, но вы всегда можете использовать обычные пакеты DatagramPackets по широковещательному адресу.