开发者

SpringBoot+Guacamole实现远程桌面教程

开发者 https://www.devze.com 2025-10-13 10:29 出处:网络 作者: 肥仔哥哥1930
目录前言技术选型远程桌面协议分析原理与协议性能与体验功能与安全使用场景小结架构选型要理解的是整体逻辑总结前言
目录
  • 前言
  • 技术选型
  • 远程桌面协议分析
    • 原理与协议
    • 性能与体验
    • 功能与安全
    • 使用场景
    • 小结
    • 架构选型
    • 要理解的是
    • 整体逻辑
  • 总结

    前言

    最近不是在想方案,就是在方案的预研上,头发越来越少啊。

    今天要跟大家分享的是坐席远程帮办,名字定义很高大,技术落地实际上就是远程桌面+语音指导。

    技术选型

    我们团队很健全,各语种的研发都有,但是就是兄弟们现在都项目缠身。

    我作为技术负责人,肯定是要自己先有方向,至少要能够在各种需求场景抛砖引玉吧。所以在远程桌面这块先行预研,先给C语种方向的兄弟整个可行性高点的方案:

    1、https://github.com/xunki/RemoteDesktopManage

    2、Java方向我自己来

    远程桌面协议分析

    其实在选型时也是各方考量,首先是要不能用人民币,用人民币要考虑投入与回报是否对等。然后就是要考量我们现在的人力储备、技术底蕴等等。

    在这过程中,首先是考量资源、带宽,然后就是针对VNC与RDP协议的抉择了。

    按说VNC协议旧,那肯定就是资源多、可参考的资料就相对多,但是对比优缺点,实在是不想到时候因为效果、延时等影响形象,免得到时候吃亏了还不讨好(按说不应该太计较个人得失,可是现实很残酷啊)。

    废话不说了,先看对比协议:

    原理与协议

    特性VNC(Virtual Network Computing)RDP(Remote Desktop Protocol)
    协议类型基于 RFB(Remote Frame Buffer)协议,传输的是屏幕像素信息微软专有协议,传输 图形对象、指令、音视频、剪贴板 等
    工作方式服务器端抓取屏幕像素并发送给客户端客户端发送操作命令,服务器端渲染界面并发送指令给客户端,客户端再绘制界面
    平台支持跨平台,Windows / linux / MACOS / 嵌入式主要是 Windows,但有 Linux/macOS 客户端支持

    性能与体验

    特性VNCRDP
    带宽占用较高,因为传输的是像素较低,因为只传输界面指令而非像素
    响应速度较慢,高分辨率时延迟明显快,延迟低,尤其在低带宽下表现更好
    图像质量像素传输,容易有模糊或延迟高质量,支持压缩和多种图形加速
    音频/多媒体一般不传输音频,需要额外设置原生支持音频重定向、多媒体优化

    功能与安全

    特性VNCRDP
    文件传输一般需要额外工具原生支持文件共享
    剪贴板共享支持,但实现依赖客户端原生支持
    多会话通常一个显示器对应一个会话(Linux 可以多个会话)Windows 支持多用户多会话
    安全性默认明文传输,需要加密(SSH/VPN)支持 TLS 加密、网络级认证(NLA)

    使用场景

    场景适合VNC适合RDP
    跨平台远程访问非 Windows 客户端有限
    高性能远程办公
    服务器管理Linux 常用Windows Server
    低带宽环境RDP 优化带宽

    小结

    VNC

    • 优点:跨平台、轻量、简单
    • 缺点:性能低、延迟大、默认不安全
    • 适合远程监控、嵌入式系统、跨平台访问

    RDP

    • 优点:低延迟、高性能、功能丰富(音频、剪贴板、文件)
    • 缺点:跨平台受限,Windows 外的体验不如原生
    • 适合 Windows 远程办公、远程服务器管理

    架构选型

    经过多方了解,既然VNC放弃,那java基于VNC的UltraVNC就不看了。

    RDP了解到的就是Guacamole,而且活力还很大哦,最近才升级。

    https://guacamole.apache.org/releases/1.6.0/

    SpringBoot+Guacamole实现远程桌面教程

    具体部署细节,看官网就行,建议用docker,部署guacamole-server/guacamole-client。

    如果不用docker,用tomcat部署client,那就有点折腾,其实,也就是tomcat放war包的地方要放扩展包,也就是处理授权的,官网提供了对应jar,放在extensions目录下。

    要理解的是

    • guacamole-server(guacd)提供服务
    • guacamole-client(RestAPI客户端)对外暴露接口

    整体逻辑

    浏览器 (html5/js)

     │ WebSocket
    
     ▼
    

    Java Web 应用 ── REST API ──► Guacamole (guacd)

                                │
    
                                ▼
    
                           Windows RDP Server
    

    我们java能做的就是在Java Web应用层做认证、连接管理等等。

    再来看看springboot的集成吧。

    就是一个普通的Springboot服务,关于Guacamole不需要额外的依赖,要说用到的,那就是Hutool的HttpUtil请求工具类。其实还有一种集成方案,那个就需要相关依赖,但是那个要自己造的轮子也多,不适合快速落地。

    RdpController

    /**
     * RDP管理
     *
     * @author zwmac
     */
    @Slf4j
    @RestController
    @RequestMapping("/rdp")
    public class RdpController {
    
        @Resource
        private GuacamoleRestService guacamoleRestService;
    
        /**
         * guacamole登录
         *
         * @param rdpInfoVo 登录信息
         * @return 登录结果
         */
        @GetMapping("/login")
        public RestResponse<?> login(@RequestBody RdpInfoVo rdpInfoVo) {
            return guacamoleRestService.login(rdpInfoVo.getUsername(), rdpInfoVo.getPassword());
        }
    
        /**
         * 列出所有连接
         *
         * @param token 登录token
         * @return 连接列表
         */
        @GetMapping("/listConnections")
        public RestResponse<?> listConnections(@RequestParam String token) {
            return guacamoleRestService.listConnections(token);
        }
    
        /**
         * 添加连接
         *
         * @param rdpConnectionInfoVo 连接信息
         * @return 添加结果
         */
        @PostMapping("/addConnection")
        public RestResponse<?> addConnection(@RequestBody RdpConnectionInfoVo rdpConnectionInfoVo) {
            return guacamoleRestService.addConnection(rdpConnectionInfoVo);
        }
    
    
    }
    

    GuacamoleRestService

    /**
     * @author zwmac
     */
    public interface GuacamoleRestService {
        /**
         * guacamole登录
         *
         * @param username 用户名
         * @param password 密码
         * @return 登录结果
         */
        RestResponse<?> login(String username, String password);
    
        /**
         * 列出所有连接
         *
         * @param token
         * @return
     TwKjU    */
        RestResponse<?> listConnections(String token);
    
        /**
         * 添加连接
         *
         * @param rdpConnectionInfoVo 连接信息
         * @return 添加结果
         */
        androidRestResponse<?> addConnection(RdpConnectionInfoVo rdpConnectionInfoVo);
    }
    

    GuacamoleRestServiceImpl

    /**
     * @author zwmac
     */
    @Service
    public class GuacamoleRestServiceImpl implements GuacamoleRestService {
    
        @Value("${guacamole.base-url}")
        private String guacamoleBaseUrl;
    
        @Value("${guacamole.datasource}")
        private String datasource;
        @Value("${guacamole.admin-user}")
    TwKjU    private String adminUserName;
    
        @Value("${guacamole.admin-password}")
        private String adminPassword;
    
        @Autowired
        private RestTemplate restTemplate;
    
    
        @Override
        public RestResponse<?> login(String username, String password) {
            if (StringUtils.isBlank(username) || StringUtils.isBlank(pass编程word)) {
                username = adminUserName;
                password = adminPassword;
            }
            Assert.isTrue(!StringUtils.isAnyBlank(username, password), "用户名或密码不能为空");
    
            Map<String, Object> formMap = new HashMap<>();
            formMap.put("username", username);
            formMap.put(TwKjU"password", password);
            HttpRequest post = HttpUtil.createPost(guacamoleBaseUrl + "/tokens");
            post.form(formMap);
            post.header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            HttpResponse execute = post.execute();
            if (execute.isOk()) {
                String executeBody = execute.body();
                return RestResponse.success(executeBody);
            }
    
            return RestResponse.fail("登录失败:" + execute.body());
        }
    
        @Override
        public RestResponse<?> listConnections(String token) {
            Assert.hasText(token, "token不能为空");
            String getUrl = guacamoleBaseUrl + "/session/data/" + datasource + "/connections?token=" + token;
            HttpRequest get = HttpUtil.createGet(getUrl);
            HttpResponse execute = get.execute();
            if (execute.isOk()) {
                String executeBody = execute.body();
                return RestResponse.success(executeBody);
            }
            return RestResponse.fail("获取连接列表失败:" + execute.body());
        }
    
        @Override
        public RestResponse<?> addConnection(RdpConnectionInfoVo rdpConnectionInfoVo) {
            //参数校验
            Assert.notNull(rdpConnectionInfoVo, "参数不能为空");
    
            return null;
        }
    }
    

    配置项

    guacamole:
      base-url: http://你的guacamole部署ip:端口/guacamole/api
      datasource: mysql   # 对应 guacamole.properties 里的配置
      admin-user: guacadmin
      admin-password: guacadmin
    

    最后,看看效果:

    Apifox接口:

    SpringBoot+Guacamole实现远程桌面教程

    guacamole服务端管理界面:

    SpringBoot+Guacamole实现远程桌面教程

    SpringBoot+Guacamole实现远程桌面教程

    远程效果:

    SpringBoot+Guacamole实现远程桌面教程

    总结

    好了,就写到这里,希望能帮到大家。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    其实还是那句话,关键的关键是要有思路,思路很重要!!!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号