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

使用jupnp在Java中发送UPnP搜索消息失败,ControlPoint为空

解决jUPnP中ControlPoint为空的问题

针对你遇到的ControlPoint为空、无法发送UPnP搜索消息的问题,核心原因是新版jUPnP的DefaultUpnpServiceConfiguration默认不再自动初始化ControlPoint,需要手动创建并关联到UpnpService实例。

修复步骤与代码调整

1. 优先使用最新jUPnP版本

建议使用2.x系列稳定版,避免旧版本的API兼容问题。

2. 修改UpnpService初始化逻辑

手动创建ControlPoint并绑定到配置,确保upnpService.getControlPoint()能返回有效实例。修改后的完整代码如下:

package xyz.necrozma.upnpplugin;

import org.bukkit.plugin.java.JavaPlugin;
import org.jupnp.DefaultUpnpServiceConfiguration;
import org.jupnp.controlpoint.ControlPoint;
import org.jupnp.controlpoint.DefaultControlPoint;
import org.jupnp.model.message.header.STAllHeader;
import org.jupnp.UpnpService;
import org.jupnp.UpnpServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class main extends JavaPlugin {

    private final Logger logger = LoggerFactory.getLogger(main.class);
    private UpnpService upnpService;
    private int port = 25565;

    @Override
    public void onEnable() {
        port = getServer().getPort();
        logger.info("Trying to open port " + port + " for UPNP");

        // 手动创建ControlPoint并绑定到配置的协议工厂
        DefaultUpnpServiceConfiguration config = new DefaultUpnpServiceConfiguration();
        ControlPoint controlPoint = new DefaultControlPoint(config.getSyncProtocolFactory());
        
        // 初始化UpnpService时传入已创建的ControlPoint
        upnpService = new UpnpServiceImpl(config, controlPoint);

        logger.info("UPNP service created, searching for devices, please wait...");

        if (controlPoint != null) {
            controlPoint.search(new STAllHeader());

            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            int deviceCount = upnpService.getRegistry().getRemoteDevices().size();
            logger.info("Search complete, found " + deviceCount + " devices.");

        } else {
            logger.error("ControlPoint is null, unable to perform search.");
        }

        upnpService.getRegistry().getRemoteDevices().forEach((remoteDevice) -> {
            logger.info("Found device: " + remoteDevice.getDisplayString());
        });
    }

    @Override
    public void onDisable() {
        logger.info("UPNP service stopping...");
        if (upnpService != null) {
            upnpService.shutdown();
        }
    }
}

关键修改点说明

  • 显式创建ControlPoint:使用DefaultControlPoint类,传入配置的协议工厂,保证ControlPoint与UpnpService使用一致的底层配置
  • 绑定ControlPoint到UpnpService:调用UpnpServiceImpl的重载构造方法,将手动创建的ControlPoint传入,替代默认的自动初始化逻辑
  • 规避版本差异问题:新版jUPnP为提升灵活性,取消了ControlPoint的自动创建,必须显式初始化后绑定才能正常使用

额外注意事项

  • 避免主线程阻塞:Thread.sleep()在Bukkit插件主线程调用会阻塞服务器运行,建议将搜索逻辑放到异步线程中执行
  • 实时监听设备:若需要实时接收设备发现/离线事件,可给UpnpService的Registry添加RegistryListener,无需依赖固定时长的sleep等待

内容的提问来源于stack exchange,提问作者Ethan James

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:23:31