背景:
2019 年 12 月 5 日, 微软宣布放弃浏览器 Edge, 转而推出一款新的浏览器, 而这款新浏览器将会采用谷歌的 Chromium 内核...
好了, 反正已经无力吐槽, 微软烂尾的项目也不是一个两个了, 之前放弃 IE 转 Edge, 现在有把 Edge 丢掉拥抱 Chromium,
彻底结束了 IE 家族; 居于这个原因, 之前项目中有使用过一些跟 IE 绑定的 ActiveX 插件, 也不得不做出改变了.
现状:
网上搜索 "web 访问远程桌面", 没有找到合适的解决方案, 基本上有以下几种:
1, 在 Google 浏览器上使用 "IE TAB" 插件, 这个插件是 Google 浏览器应用商店上的插件; 试过之后确实可以运行 IE 上的 ActiveX 插件;
缺点:
1) 最重要的, 需要翻墙, 由于国内不能直接方法 Google 应用商店, 所以要安装这个插件必须翻墙出去;
这在大部分情况下就不适合, 因为很多人不会;
2) 操作冗余, 每次打开插件都需要在 Google 菜单栏点击一个小按钮, 如何页面才会跟着转换, 这会很奇怪;
3) 兼容性糟糕, 如果 JS 在不同的 IE 浏览器下调试通过的, 那在 Google 上也需要右键 "IE TAB" 按钮, 找到属性栏,
选择对应的 IE 版本; 这体验就非常不好, 因为很多用户根本不会使用浏览器插件, 更不要说去设置参数
4) 还是翻墙, 这个插件居然还引用了一个 Ajax 的 JS 文件, 这个文件刚好是在 Google 域名下的; 这就会导致设置插件
属性的时候不翻墙根本打不开;
5) 放弃..
2, 使用 IIS 的远程桌面, 基于 "Remote desktop web connection" 技术, 详细可浏览这篇文章 "远程桌面 web 连接"
缺点:
1) 页面和操作步骤不可定制, 只能使用 IIS 封装好的页面
2) 每次离开需要重新输入账户, 很不方便
3) 需要服务器该功能支持, 以及各种配置操作
4) 优先级低下, 放弃...
3, 微软最新的退出的 "Remote Desktop" 技术, 详细可浏览这篇文章 "微软宣推 Remote Desktop 远程桌面网页版"
以及官方介绍:"为用户设置远程桌面 Web 客户端"
缺点:
1) 需要 Windows service 2016 火灾 Windows service 2019, 并且安装 RD 网关;
2) 配置太繁琐, 非人类操作, 看官方的安装配置介绍的非常不清晰, 各种配置, 各种工具支持,
各种命令, 要是决定使用这个方案, 怕是会忍不住砸了电脑;
3) 放弃放弃.., 狗命要紧.
4,guacamole, 说是 html5 的远程 Web 应用, 支持 rdp,vnc,SSH, 在 Windows 和 Linux 下都能运行,
需要很多配置, 依赖等, 支持 docker 下部署
缺点:
1) 门槛较高, 非 Linux 原生码农使用起来可能会非常烦躁, 而且安装包还不小, 几百 M 操作复杂
2) 而且好像只支持 Java 的? 不是很确定.
3) 本人没有使用过这种方式, 不过看起来这个在 Web 端访问远程桌面还是做的比较好的, 国内外知名度很高
4).net 下没有找到有用的资料, 高手可以尝试一番
5) 放弃,,
5,remote spark 的 spark gateway, 这个我一点都不了解, 网上搜到的, 具体查看这篇文章 "HTML5 远程工具"
缺点:
1) 资料太少, 太小众, 出问题都不知道怎么改
2) 放弃
6, 那就是使用 ActiveX 浏览器插件了, 但是现在以及不合适了, ActiveX 恐怕要彻底退出历史舞台;
功能需求:
基于以上的各种调研, 始终没有找到一个合适的, 容易上手, 部署简单, 使用方便的 Web 端访问服务器的方案;
因为我始终无法理解为什么把这种插件安装以及使用搞的那么复杂, 完全没有必要啊?
首先我们列举一下我们想要的功能:
1) 屏幕共享, 在 Web 端能实时查看服务器的屏幕信息
2) 鼠标事件, 需要支持单击, 双击, 右键, 光标移动, 支持这 4 个功能足够了
3) 键盘事件, 需要支持键盘按下, 松开, 组合键 (比如切换输入法)
4) 拖动窗体, 拖动选择文本
如果支持以上 4 点那就足够了, 基本满足用户 99% 交互操作.
自研:
现在需求有了, 那干脆也不继续找现有别人的产品了, 既然没有, 那就自己搞一个出来.
1, 工具基本架构
2, 实现原理
1)Web 端使用 html5 的 websocket 与 Web 后台通信, Web 后台与服务端使用 TCP 协议通信
2) 定制传输协议, 发送命令与接收数据包需要一个传输协议保证数据完整, 组包, 检验包
3)Web 端接收到后台推送过来的频幕位图流数据, 直接在 img 或 canvas 元素上渲染出来;
4) 服务端接收到前端命令, 转成各种方式实现相应操作
3, 前端功能列举
1)websocket, 接收到数据包赋值给 img
- var wsImpl = Windows.WebSocket || Windows.MozWebSocket;
- var ws = new wsImpl('ws://localhost:7184/');
- ws.onmessage = function (evt) {
- var image = document.getElementById("desktop");
- image.src = evt.data;
- ...
- }
2) 键盘事件
- $(Windows).keypress(function (event) {
- ws.send("{'action':3,'c':'" + event.which + "'}");
- });
- $(Windows).keydown(function (event) {
- if (event.key == "Shift") {
- if (event.ctrlKey) {
- ws.send("{'action':3,'c':'" + 201 + "'}");
- }
- else {
- ws.send("{'action':3,'c':'" + 200 + "'}");
- }
- }
- });
3) 鼠标事件
- $(desktop).mousemove(function (e) {
- sendXY(e.offsetX, e.offsetY);
- });
- $(desktop).mousedown(function (event) {
- sendMousedown(event);
- });
- $(desktop).mouseup(function (event) {
- sendMouseup(event);
- });
- $(desktop).click(function (e) {
- sendClick();
- });
- $(desktop).dblclick(function (e) {
- sendDoubleClick();
- });
- ...
4) 前端 HTML
- <!DOCTYPE HTML>
- <HTML xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>
- </title>
- <script src="../Scripts/jquery-1.10.2.js">
- </script>
- <script src="../Scripts/jquery.webDesktop.min.js">
- </script>
- <script type="text/javascript">
- $(function() {
- $(".desktop_login").click(function(e) {
- $(".webDesktop").desktop({
- 'ip': 'localhost'
- });
- });
- });
- </script>
- <style>
- body { padding: 0px; margin: 0px; background-color: #000033; color: white;
- font-weight: bold; } .main { width: 100%; height: 100%; } .webDesktop {
- text-align: left; } .tip { margin-left: 100px; margin-top: 100px; font-size:
- 22px; } .user { clear: both; min-height: 100px; } .desktop_name { margin-left:
- 100px; margin-top: 36px; font-size: 18px; float: left; } .desktop_login
- { padding: 3px 20px 3px 20px; margin-left: 30px; margin-top: 30px; font-size:
- 20px; float: left; border: 3px solid #ffffff; cursor: pointer; } .time
- { position: fixed; left: 100px; bottom: 250px; width: 100%; height: 50px;
- z-index: 9999; font-size: 120px; font-weight: normal; } .day { position:
- fixed; left: 100px; bottom: 80px; width: 100%; height: 50px; z-index: 9998;
- font-size: 55px; font-weight: normal; }
- </style>
- </head>
- <body onselectstart="return false">
- <div class="webDesktop">
- <div class="tip">
- 按下 "登录服务器" 进入.
- </div>
- <div class="user">
- <div class="desktop_name">
- Administrator 已登录.
- </div>
- <div class="desktop_login">
- 登录服务器
- </div>
- </div>
- <div class="time">
- 15:19
- </div>
- <div class="day">
- 10 月 21 日, 星期一
- </div>
- </div>
- </body>
- </HTML>
View Code
5, 后台界面
1) 处理前端命令
- Task.Run(() =>
- {
- while (true)
- {
- try
- {
- if (isBreak) break;
- if (clientSocket == null || !clientSocket.Connected)
- {
- break;
- }
- var data = new byte[64];
- var length = clientSocket.Receive(data);
- if (length> 0)
- {
- log.Clear();
- var cmd = StringHelper.BytesToStruct<SDesktop>(data, typeof(SDesktop));
- if (cmd.action != 0x02)
- {
- lastActionTime = DateTime.Now;
- }
- log.AppendLine(clientSocket.RemoteEndPoint.ToString());
- log.AppendFormat(">> action:{0},x:{1},y:{2},c:{3},k:{4}", cmd.action, cmd.x, cmd.y, cmd.c, cmd.k).AppendLine();
- if (cmd.action == 0x03)
- {
- if (cmd.k == 201 || cmd.k == 200)
- {
- SwitchToLanguageMode(ref log);
- }
- else
- {
- SendKeys.SendWait(cmd.c.ToString());
- log.AppendFormat(">> SendKeys:({0})", cmd.c).AppendLine();
- }
- }
- else
- {
- Desktop.Cmd(cmd, log);
- }
- AppendLog(log.ToString());
- }
- }
- catch (Exception ex)
- {
- AppendLog(clientSocket.RemoteEndPoint.ToString() + ">> Receive 出错, ex:" + ex.Message);
- }
- }
- });
- View Code
2) 处理屏幕数据
- Task.Run(() =>
- {
- while (true)
- {
- try
- {
- if (isBreak) break;
- if (clientSocket == null || !clientSocket.Connected)
- {
- break;
- }
- var screen = GetScreen();
- for (var i = 0; i <screen.Length; i = i + packsize)
- {
- lock (objSocketSend)
- {
- if (screen.Length - i < packsize)
- {
- clientSocket.Send(screen, i, screen.Length - i, SocketFlags.None);
- }
- else
- {
- clientSocket.Send(screen, i, packsize, SocketFlags.None);
- }
- }
- }
- }
- catch (Exception ex)
- {
- AppendLog(clientSocket.RemoteEndPoint.ToString() + ">> Send 出错, ex:" + ex.Message);
- }
- var tm = (DateTime.Now - lastActionTime).TotalMilliseconds;
- if (tm> 2000)
- {
- var speed = cbSpeed.Text.ToInt();
- Thread.Sleep(speed);
- var content = string.Format("{0}>> Screen.{1},tm:{2}", clientSocket.RemoteEndPoint.ToString(), speed, tm);
- AppendLog(content);
- }
- else
- {
- Thread.Sleep(10);
- AppendLog(clientSocket.RemoteEndPoint.ToString() + ">> Screen,tm:" + tm);
- }
- }
- connCount--;
- });
- View Code
最终效果:
1) 鼠标事件
1) 键盘事件
来源: https://www.cnblogs.com/lanxiaoke/p/11721174.html