You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法连接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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:46:40