使用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
相关产品推荐
相关产品推荐

