The pitfalls for sending broadcast packets through Android Socket
The Socket broadcast package is often used for mutual discovery and message transmission between two devices in the LAN. During Android Application Development, such requirements are often met. For example: between Two Android devices, smart hardware such as Android and wristband, and between Android and Windows. This article mainly introduces the programming precautions when using Socket in Android to develop the broadcast package program, and the solution. First, we provide a sample code for Android to send a broadcast package:
DatagramSocket socket = new DatagramSocket(8000);socket.setBroadcast(true);InetAddress addr = InetAddress.getByName("255.255.255.255");byte[] buffer = "Hello World".getBytes();DatagramPacket packet = new DatagramPacket(buffer,buffer.length);packet.setAddress(addr);packet.setPort(8086);socket.send(packet);
The following are some points to note: 1. do not send broadcast packets in the main thread. Of course, this Android developer should know that he cannot perform any network access-related operations in the UI thread, because the sending of a broadcast package is also a network operation, it must be executed in a separate thread. 2. The broadcast address is not recommended in the above Code "broadcast packet 255.255.255". The target address of the broadcast package is set to "broadcast packet 255.255". In fact, this is not a recommended practice. "Broadcast 255.255.255" is a restricted broadcast address. It is often used when a computer does not know its IP address. For example, when a device is started, it requests an address from the DHCP server. Generally, the router does not forward broadcast packets whose destination is a restricted broadcast address. In addition, some routers/Wi-Fi hotspots do not support this broadcast address (for example, when using Android phones for Wi-Fi hotspots ), therefore, an "ENETUNREACH (Network is unreachable)" exception occurs in the program. Therefore, we recommend that you use a direct broadcast address to ensure that the program successfully sends a broadcast packet. For example, the current IP address is 192.168.1.100, when the subnet mask is 255.255.255.0, the broadcast address is 192.168.1.255. (The specific calculation method is not expanded here. For more information, see related books on computer networks ). Then, how can we get the direct broadcast address of this segment? The following is the code shared by Daniel in stackoverflow:
public static InetAddress getBroadcastAddress(Context context) throws UnknownHostException { WifiManager wifi = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); DhcpInfo dhcp = wifi.getDhcpInfo(); if(dhcp==null) { return InetAddress.getByName("255.255.255.255"); } 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);}
You can directly use this function to obtain the correct "broadcast address" and set it to the DatagramPacket object through the setAddress function. 3. the broadcast address when Android is set as a Wi-Fi hotspot is a big pitfall. When Android devices are set as Wi-Fi hotspots, the address obtained by the above function is "0.0.0.0". Therefore, we need to find out what the IP address is when the Android device is set to a Wi-Fi hotspot? Some people have studied the underlying Android source code and found that when the Android device is set to a Wi-Fi hotspot, its IP address is written to the source code by hardcode, and its IP address is "192.168.43.1 ", the corresponding broadcast address is "192.168.43.255". Therefore, we need to write a function to determine whether the current Android mobile phone is in Wi-Fi hotspot mode. If yes, the broadcast address shown above should be used. The sample code is provided here:
protected static Boolean isWifiApEnabled(Context context) { try { WifiManager manager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); Method method = manager.getClass().getMethod("isWifiApEnabled"); return (Boolean)method.invoke(manager); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace();} return false;}
The Android SDK is not open to determine whether the API is in the hotspot mode. Therefore, we need to get the API through reflection. In addition, pay attention to adding permissions:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
4. Summary