Вещание через Wi-Fi Direct

Я рассматриваю возможность трансляции через соединение Wi-Fi Direct между несколькими устройствами Android. Я создал простое приложение для рассылки сообщений, чтобы проверить, работает оно или нет, но до сих пор мне не удалось передать сообщение. Когда я пытаюсь отправить пакет, я получаю SocketException (сеть недоступна):

03-20 13:23:00.148: E/UdpBroadcaster(4180): sendto failed: ENETUNREACH (Network is unreachable)
03-20 13:23:00.148: E/UdpBroadcaster(4180): java.net.SocketException: sendto failed: ENETUNREACH (Network is unreachable)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:496)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.IoBridge.sendto(IoBridge.java:465)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:182)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at java.net.DatagramSocket.send(DatagramSocket.java:307)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at com.example.android.wifidirect.UdpBroadcaster.sendMessage(UdpBroadcaster.java:59)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at com.example.android.wifidirect.UdpBroadcaster.run(UdpBroadcaster.java:44)
03-20 13:23:00.148: E/UdpBroadcaster(4180): Caused by: libcore.io.ErrnoException: sendto failed: ENETUNREACH (Network is unreachable)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.Posix.sendtoBytes(Native Method)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.Posix.sendto(Posix.java:146)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:177)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     at libcore.io.IoBridge.sendto(IoBridge.java:463)
03-20 13:23:00.148: E/UdpBroadcaster(4180):     ... 4 more

В этом суть моего кода:

InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
int port = 8888;

DatagramSocket socket = new DatagramSocket(port);
socket.setBroadcast(true);
socket.connect(broadcastAddress, port);

String message = "Hello";
byte[] buffer = message.getBytes();

DatagramPacket packet = new DatagramPacket(
        buffer, buffer.length, broadcastAddress, port);

try {
    socket.send(packet); // <----- Causes a SocketException
} catch (IOException e) {
    Log.e(TAG, e.getMessage(), e);
}

В этом сообщении предполагается, что вещание через Wi-Fi Direct должно быть возможно.

Кто-нибудь знает, действительно ли работает трансляция через Wi-Fi Direct на устройствах Android? Если это должно работать, что я делаю неправильно?

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


Обновить

После использования функции getBroadcastAddress(), предложенной Romain Hippo, исключение SocketException исчезло, и кажется, что вещание работает как положено. Однако у меня проблемы с приемом трансляции на втором устройстве.

Я использую следующий код для получения трансляции:

DatagramSocket socket = null;
try {
    socket = new DatagramSocket(8888);
    socket.setBroadcast(true); // Not needed?
    socket.setSoTimeout(200);

    DatagramPacket packet = null;
    while (!mStopping) {
        byte[] buffer = new byte[1024];
        packet = new DatagramPacket(buffer, buffer.length);

        try {
            socket.receive(packet);

            if (packet.getData().length > 0) {
                String receivedString = new String(packet.getData());

                Log.i(TAG, "Received string: " + receivedString);
            }
        } catch (InterruptedIOException e) { /* Ignore */ }
    }
} catch (IOException e) {
    Log.e(TAG, e.getMessage(), e);
} finally {
    if (socket != null)
        socket.close();
}

Я также пытался добавить групповой адрес к DatagramSocket, добавив InetAddress.getByName("0.0.0.0") в качестве аргумента, но безуспешно.

Предложения?


person KatoStoelen    schedule 20.03.2013    source источник
comment
Кстати: Посмотрите эту статью: developer.android.com/training /подключить-устройства-беспроводным способом/   -  person Grim    schedule 16.05.2015


Ответы (1)


Бессовестно украдено с сайта https://code.google.com/p/boxeeremote/wiki/AndroidUDP

Попробуйте подключиться к сети следующим образом:

InetAddress getBroadcastAddress() throws IOException {
    WifiManager wifi = mContext.getSystemService(Context.WIFI_SERVICE);
    DhcpInfo dhcp = wifi.getDhcpInfo();
    // handle null somehow

    int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
    byte[] quads = new byte[4];
    for (int k = 0; k < 4; k++)
      quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
    return InetAddress.getByAddress(quads);
}  

Затем попробуйте отправить пакет следующим образом:

DatagramSocket socket = new DatagramSocket(PORT);
socket.setBroadcast(true);
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
    getBroadcastAddress(), PORT);
socket.send(packet);

// If you want to listen for a response ...
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);

Изменить: с той же страницы, чтобы прочитать, попробуйте это...

WifiManager wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
MulticastLock lock = wifi.createMulticastLock("dk.aboaya.pingpong");
lock.acquire();
serverSocket = new DatagramSocket(19876);
serverSocket.setSoTimeout(15000); //15 sec wait for the client to connect
byte[] data = new byte[UDPBatPositionUpdater.secretWord.length()]; 
DatagramPacket packet = new DatagramPacket(data, data.length);
serverSocket.receive(packet);
lock.release();
String s = new String(packet.getData());
System.out.println(s);

Помните, что для его работы вам необходимо следующее разрешение:
‹uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/›

person Romain Hippeau    schedule 20.03.2013
comment
Исключение SocketException исчезло после использования этой функции для получения широковещательного адреса, и, похоже, широковещательная рассылка работает, но у меня возникают проблемы с получением широковещательной передачи на втором устройстве. Таким же образом я инициализирую DatagramSocket на принимающем устройстве. Я также попытался использовать групповой адрес для получателя DatagramSocket, добавив InetAddress.getByName("0.0.0.0") в качестве аргумента. Не повезло. - person KatoStoelen; 20.03.2013
comment
@user2190832 user2190832 добавил в мой ответ некоторые подробности, чтобы прочитать UDP. - person Romain Hippeau; 22.03.2013
comment
Код работает отлично, спасибо! Некоторые подробности об устройствах: я создаю свои собственные библиотеки для обработки этого сообщения на основе этого кода. В настоящее время я использую порт 8888. Мой Nexus 5 может отправлять и получать сообщения. Мой Moto G может только отправлять посылки (и получать свои, но не формировать другие устройства). Недавно я пробовал в Samsung Galaxy S2 и могу отправлять и получать посылки. Каким-то образом Motorola блокирует входящие трансляции. Я пробовал в двух разных Moto G, один сгнил с определенными политиками брандмауэра и один сток, но не повезло. - person Rudolf Real; 05.12.2014