无法连接Yeelight WiFi彩光灯泡:Android控制应用连接超时问题
解决Yeelight SSDP发现时的ConnectionTimeoutException问题
我明白你现在卡在Yeelight WiFi灯泡的SSDP发现环节了,明明在同一WiFi下却一直超时,这种情况确实挺让人挠头的。咱们从代码和系统配置两方面来排查问题:
一、代码里的几个关键问题
1. SSDP消息格式不完整
HTTP协议要求头部必须以空行结尾,也就是最后一个头部字段后要再加一个\r\n。你的代码里最后一行是ST: wifi_bulb,没有添加结尾的换行,这会导致Yeelight灯泡无法正确解析你的M-SEARCH请求,自然不会给你回包,最终触发超时。
2. 没有加入组播组
普通的DatagramSocket默认不会接收组播包,你需要显式让Socket加入239.255.255.250这个组播地址,这样才能收到灯泡发回的组播响应。
3. 异常处理不够严谨
你的代码里嵌套了try-catch,外层catch会吃掉内层的异常,不利于排查问题;另外clientSocket.close()放在try块外面,万一Socket没创建成功会导致空指针。
二、修正后的代码示例
public void connectDevice() { byte[] sendData; byte[] receiveData = new byte[1024]; MulticastSocket clientSocket = null; final String NL = "\r\n"; try { // 构建正确的SSDP M-SEARCH请求 StringBuilder mSearch = new StringBuilder(); mSearch.append("M-SEARCH * HTTP/1.1").append(NL); mSearch.append("HOST: 239.255.255.250:1982").append(NL); mSearch.append("MAN: \"ssdp:discover\"").append(NL); mSearch.append("ST: wifi_bulb").append(NL); // 每个字段后加换行 mSearch.append(NL); // 最后加空行,结束HTTP头部 sendData = mSearch.toString().getBytes(); InetAddress group = InetAddress.getByName("239.255.255.250"); DatagramPacket sendPacket = new DatagramPacket( sendData, sendData.length, group, 1982); // 使用MulticastSocket而非普通DatagramSocket clientSocket = new MulticastSocket(1982); // 绑定到SSDP端口,方便接收响应 clientSocket.joinGroup(group); // 加入组播组 clientSocket.setSoTimeout(10000); // 设置10秒超时足够了 // 发送搜索请求 clientSocket.send(sendPacket); Log.d("Yeelight", "已发送SSDP搜索请求"); // 接收响应 DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); clientSocket.receive(receivePacket); // 解析响应内容 String response = new String(receivePacket.getData(), 0, receivePacket.getLength()); Log.d("Yeelight", "收到响应:\n" + response); } catch (SocketTimeoutException e) { Log.e("Yeelight", "搜索超时,请检查灯泡状态和网络配置"); e.printStackTrace(); } catch (IOException e) { Log.e("Yeelight", "网络IO异常"); e.printStackTrace(); } finally { // 确保Socket关闭 if (clientSocket != null && !clientSocket.isClosed()) { try { clientSocket.leaveGroup(InetAddress.getByName("239.255.255.250")); clientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
三、必须配置的Android权限
Android系统对组播和网络操作有严格的权限限制,你需要在AndroidManifest.xml里添加以下权限,并且在Android 6.0及以上版本动态申请危险权限:
<!-- 基础网络权限 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 获取WiFi状态 --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 允许修改WiFi组播状态,这是接收组播包的关键 --> <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> <!-- Android 10+需要后台网络权限 --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
注意:CHANGE_WIFI_MULTICAST_STATE是普通权限不需要动态申请,但INTERNET在某些版本可能需要,另外如果你的应用在后台运行,Android 10+需要后台位置权限才能正常使用网络。
四、路由器配置检查
D-Link DIR 600M路由器可能默认限制了组播包的转发,你可以登录路由器后台检查:
- 找到高级设置里的组播选项,确保IGMP Snooping是开启状态(或者尝试关闭,有些老设备开启反而有问题)
- 确认路由器没有开启AP隔离功能,AP隔离会阻止同一WiFi下的设备互相通信
最后补充几个小提示
- 确保Yeelight灯泡处于正常工作状态,并且已经完成WiFi配网(可以用官方APP确认)
- 尽量不要在主线程中执行网络操作,把这段代码放到子线程或者用Coroutines、AsyncTask处理,避免ANR
- 可以尝试用Wireshark抓包,看看M-SEARCH请求有没有发出去,以及有没有收到灯泡的响应,这是排查网络问题的终极办法
内容的提问来源于stack exchange,提问作者Naveen Sharma
相关产品推荐
相关产品推荐

