Отправлять широковещательный UDP, но не получать его на других устройствах Android
Я пытаюсь разработать приложение, которое отправляет некоторые широковещательные сообщения и получает ответы от других устройств Android. У меня возникают проблемы с получением сообщений UDP с других устройств. Я должен упомянуть, что этот код работал на Gingerbread, но на JellyBean он больше не работает, и я не знаю, в чем проблема.
Здесь я отправляю широковещательное сообщение (я знаю, что другие устройства прослушивают порт 5000):
private void sendUDPMessage(String msg) {
try {
DatagramSocket clientSocket = new DatagramSocket();
clientSocket.setBroadcast(true);
InetAddress address = InetAddress.getByName(Utils.getBroadcastAddress());
byte[] sendData;
sendData = msg.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, address, 5000);
clientSocket.send(sendPacket);
clientSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
И вот где я его получаю:
private void start_UDP()
{
try {
serverSocketUDP = new DatagramSocket(5000);
}
catch (Exception e) {
Log.i(LOGTAG, "Exception opening DatagramSocket UDP");
}
final byte[] receiveData = new byte[1024];
while(runningUDP) {
Log.d(LOGTAG, "Waiting for Broadcast request in ServerUDP.");
final DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocketUDP.receive(receivePacket);
byte[] sendData = new byte[1024];
InetAddress address = receivePacket.getAddress();
int port = receivePacket.getPort();
if(!receivePacket.getAddress().getHostAddress().equals(Utils.getLocalIpAddress()))
{
String req = new String(receivePacket.getData(), 0, receivePacket.getLength());
Log.d(LOGTAG, "Received UDP message : "+req+" from: "+receivePacket.getAddress().getHostAddress());
}
}// while ends
}//method ends
Я должен упомянуть, что эти 2 функции разделены в 2 разных потоках, поэтому я могу отправлять и получать одновременно.
Я также получаю следующие блокировки:
powerManager =(PowerManager)context.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK ,LOGTAG); // PARTIAL_WAKE_LOCK Only keeps CPU on
wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
wifiLock = wifiManager.createWifiLock(3, LOGTAG);
multicastLock = wifiManager.createMulticastLock(LOGTAG);
wakeLock.acquire();
multicastLock.acquire();
wifiLock.acquire();
И разрешения в файле манифеста:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
Я тестировал, если сообщения отправляются с помощью wireshark и tcpdump, и они отправляются. Более того, что еще более странно, я получаю широковещательные сообщения, которые я отправляю (но я их отбрасываю, потому что мне не нужно обрабатывать сообщения, отправленные от себя), но я не получаю широковещательные сообщения, отправленные с других устройств (которые должны иметь в том же формате, только исходный адрес будет отличаться и содержащее сообщение в любом случае не должно влиять на широковещательное сообщение).
Пожалуйста, дайте мне знать, если у вас есть какие-то идеи, потому что у меня действительно закончилось все, что я мог попробовать. Любая помощь будет оценена по достоинству. Спасибо!
EDIT:
Я сделал несколько тестов, и даже если я запускаю на каждом из телефонов ifconfig wlan0, и он говорит что-то вроде
ifconfig wlan0
wlan0: ip 169.254.17.28 mask 255.255.0.0 flags [up broadcast multicast]
что означает, что интерфейс активен, а IP установлен и может принимать широковещательные сообщения и многоадресные сообщения, но когда я использую
InetAddress in=InetAddress.getByName("169.254.17.28");
if (in.isReachable(1000))
Log.i(LOGTAG, "host is reachable");
else
Log.i(LOGTAG, "host is not reachable");
Показывает, что хост журналов недоступен.
Здесь я включаю Wi-fi
private void startWifiAdhoc() {
WifiManager wifiManager = (WifiManager)SharingFileService.context.getSystemService(Context.WIFI_SERVICE);
String command="";
if (condWifiAdhoc == false) {
condWifiAdhoc=true;
wifiInterface = Utils.getWifiInterface();
wifiManager.setWifiEnabled(true);
localIP = Utils.getLinkLocalAddress();
}
else
{
wifiManager.setWifiEnabled(true);
localIP = Utils.getLinkLocalAddress();
}
// Set wifi ad-hoc
command = context.getFilesDir().getPath()
+ "/iwconfig " + wifiInterface + " mode ad-hoc essid "
+ "mcp" + " channel " + "1" + " commit\n";
Log.i(LOGTAG, command);
Utils.rootExec(command);
Log.i(LOGTAG, "Ip address used :" + localIP);
command = context.getFilesDir().getPath()
+ "/ifconfig " + wifiInterface + " " + localIP
+ " netmask 255.255.0.0 up\n";
Log.i(LOGTAG, command);
Utils.rootExec(command);
}
Ответы
Ответ 1
Я получил эту работу, используя метод, описанный здесь, для расчета широковещательного адреса: https://code.google.com/p/boxeeremote/wiki/AndroidUDP
Здесь мой приемник:
try {
//Keep a socket open to listen to all the UDP trafic that is destined for this port
socket = new DatagramSocket(Constants.PORT, InetAddress.getByName("0.0.0.0"));
socket.setBroadcast(true);
while (true) {
Log.i(TAG,"Ready to receive broadcast packets!");
//Receive a packet
byte[] recvBuf = new byte[15000];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
socket.receive(packet);
//Packet received
Log.i(TAG, "Packet received from: " + packet.getAddress().getHostAddress());
String data = new String(packet.getData()).trim();
Log.i(TAG, "Packet received; data: " + data);
// Send the packet data back to the UI thread
Intent localIntent = new Intent(Constants.BROADCAST_ACTION)
// Puts the data into the Intent
.putExtra(Constants.EXTENDED_DATA_STATUS, data);
// Broadcasts the Intent to receivers in this app.
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
}
} catch (IOException ex) {
Log.i(TAG, "Oops" + ex.getMessage());
}
И вот мой отправитель:
public void sendBroadcast(String messageStr) {
// Hack Prevent crash (sending should be done using an async task)
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
try {
//Open a random port to send the package
DatagramSocket socket = new DatagramSocket();
socket.setBroadcast(true);
byte[] sendData = messageStr.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, getBroadcastAddress(), Constants.PORT);
socket.send(sendPacket);
System.out.println(getClass().getName() + "Broadcast packet sent to: " + getBroadcastAddress().getHostAddress());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.getMessage());
}
}
InetAddress getBroadcastAddress() throws IOException {
WifiManager wifi = (WifiManager) 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);
}
Ответ 2
Я столкнулся со своим сообщением при попытке решить подобную проблему. Вы заработали свой материал?
В моем случае я пытался получить Nexus 7 (первый ген с желе Bean 4.3) и Nexus One (Gingerbread 2.3.6), разговаривающий друг с другом через UDP. Первоначально мое приложение, работающее на обоих устройствах, успешно связывалось, но только с односторонней связью с телефона на планшет. У меня было только одно разрешение в манифесте: ИНТЕРНЕТ. Связь с планшета на телефон начала работать, как только я добавил разрешение ACCESS_NETWORK_STATE для манифеста.
Итак, по какой-то причине Nexus 7 доволен только разрешением INTERNET для отправки и приема UDP-пакетов (ну, по крайней мере, моей конкретной реализации). Nexus One отправит только с разрешения INTERNET, но не получит, если не будет предоставлено разрешение ACCESS_NETWORK_STATE.
Ваш код похож на мой (я не признаю ваши вызовы "UTILS.", однако). В моем случае, однако, для целей тестирования я жестко закодировал широковещательный адрес (192.168.n.255). Я нахожусь в точке доступа, когда вы находитесь в сети adhoc. Возможно, это также имеет некоторый эффект.