zoukankan      html  css  js  c++  java
  • 在web端使用html5访问远程桌面

    背景:

      2018年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 = window.WebSocket || window.MozWebSocket;
        var ws = new wsImpl('ws://localhost:7184/');
    
        ws.onmessage = function (evt) {
                var image = document.getElementById("desktop");
                image.src = evt.data;
                ...
        }
    

      2)键盘事件

        $(window).keypress(function (event) {
            ws.send("{'action':3,'c':'" + event.which + "'}");
        });
    
        $(window).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

     1 <!DOCTYPE html>
     2 <html xmlns="http://www.w3.org/1999/xhtml">
     3 <head>
     4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     5     <title></title>
     6     <script src="../Scripts/jquery-1.10.2.js"></script>
     7     <script src="../Scripts/jquery.webDesktop.min.js"></script>
     8     <script type="text/javascript">
     9         $(function () {
    10             $(".desktop_login").click(function (e) {
    11                 $(".webDesktop").desktop({ 'ip': 'localhost' });
    12             });
    13         });
    14     </script>
    15 
    16     <style>
    17         body {
    18             padding: 0px;
    19             margin: 0px;
    20             background-color: #000033;
    21             color: white;
    22             font-weight: bold;
    23         }
    24 
    25         .main {
    26             width: 100%;
    27             height: 100%;
    28         }
    29 
    30         .webDesktop {
    31             text-align: left;
    32         }
    33 
    34         .tip {
    35             margin-left: 100px;
    36             margin-top: 100px;
    37             font-size: 22px;
    38         }
    39 
    40         .user {
    41             clear: both;
    42             min-height: 100px;
    43         }
    44 
    45         .desktop_name {
    46             margin-left: 100px;
    47             margin-top: 36px;
    48             font-size: 18px;
    49             float: left;
    50         }
    51 
    52         .desktop_login {
    53             padding: 3px 20px 3px 20px;
    54             margin-left: 30px;
    55             margin-top: 30px;
    56             font-size: 20px;
    57             float: left;
    58             border: 3px solid #ffffff;
    59             cursor: pointer;
    60         }
    61 
    62         .time {
    63             position: fixed;
    64             left: 100px;
    65             bottom: 250px;
    66             width: 100%;
    67             height: 50px;
    68             z-index: 9999;
    69             font-size: 120px;
    70             font-weight: normal;
    71         }
    72 
    73         .day {
    74             position: fixed;
    75             left: 100px;
    76             bottom: 80px;
    77             width: 100%;
    78             height: 50px;
    79             z-index: 9998;
    80             font-size: 55px;
    81             font-weight: normal;
    82         }
    83     </style>
    84 </head>
    85 
    86 <body onselectstart="return false">
    87     <div class="webDesktop">
    88         <div class="tip">按下 "登录服务器" 进入。</div>
    89         <div class="user">
    90             <div class="desktop_name">Administrator 已登录。</div>
    91             <div class="desktop_login">登录服务器</div>
    92         </div>
    93         <div class="time">15:19</div>
    94         <div class="day">10月21日, 星期一</div>
    95     </div>
    96 </body>
    97 </html>
    View Code

       5、后台界面

       1)处理前端命令

     1 Task.Run(() =>
     2 {
     3     while (true)
     4     {
     5         try
     6         {
     7             if (isBreak) break;
     8 
     9             if (clientSocket == null || !clientSocket.Connected)
    10             {
    11                 break;
    12             }
    13 
    14             var data = new byte[64];
    15             var length = clientSocket.Receive(data);
    16             if (length > 0)
    17             {
    18                 log.Clear();
    19 
    20                 var cmd = StringHelper.BytesToStruct<SDesktop>(data, typeof(SDesktop));
    21                 if (cmd.action != 0x02)
    22                 {
    23                     lastActionTime = DateTime.Now;
    24                 }
    25                 log.AppendLine(clientSocket.RemoteEndPoint.ToString());
    26                 log.AppendFormat(">> action:{0},x:{1},y:{2},c:{3},k:{4}", cmd.action, cmd.x, cmd.y, cmd.c, cmd.k).AppendLine();
    27 
    28                 if (cmd.action == 0x03)
    29                 {
    30                     if (cmd.k == 201 || cmd.k == 200)
    31                     {
    32                         SwitchToLanguageMode(ref log);
    33                     }
    34                     else
    35                     {
    36                         SendKeys.SendWait(cmd.c.ToString());
    37                         log.AppendFormat(">> SendKeys:({0})", cmd.c).AppendLine();
    38                     }
    39                 }
    40                 else
    41                 {
    42                     Desktop.Cmd(cmd, log);
    43                 }
    44 
    45                 AppendLog(log.ToString());
    46             }
    47         }
    48         catch (Exception ex)
    49         {
    50             AppendLog(clientSocket.RemoteEndPoint.ToString() + " >> Receive出错,ex:" + ex.Message);
    51         }
    52     }
    53 });
    View Code

      2)处理屏幕数据

     1 Task.Run(() =>
     2 {
     3     while (true)
     4     {
     5         try
     6         {
     7             if (isBreak) break;
     8 
     9             if (clientSocket == null || !clientSocket.Connected)
    10             {
    11                 break;
    12             }
    13 
    14             var screen = GetScreen();
    15             for (var i = 0; i < screen.Length; i = i + packsize)
    16             {
    17                 lock (objSocketSend)
    18                 {
    19                     if (screen.Length - i < packsize)
    20                     {
    21                         clientSocket.Send(screen, i, screen.Length - i, SocketFlags.None);
    22                     }
    23                     else
    24                     {
    25                         clientSocket.Send(screen, i, packsize, SocketFlags.None);
    26                     }
    27                 }
    28             }
    29         }
    30         catch (Exception ex)
    31         {
    32             AppendLog(clientSocket.RemoteEndPoint.ToString() + " >> Send出错,ex:" + ex.Message);
    33         }
    34 
    35         var tm = (DateTime.Now - lastActionTime).TotalMilliseconds;
    36         if (tm > 2000)
    37         {
    38             var speed = cbSpeed.Text.ToInt();
    39             Thread.Sleep(speed);
    40 
    41             var content = string.Format("{0} >> Screen.{1},tm:{2}", clientSocket.RemoteEndPoint.ToString(), speed, tm);
    42             AppendLog(content);
    43         }
    44         else
    45         {
    46             Thread.Sleep(10);
    47             AppendLog(clientSocket.RemoteEndPoint.ToString() + " >> Screen,tm:" + tm);
    48         }
    49     }
    50 
    51     connCount--;
    52 });
    View Code

     最终效果:

    1)鼠标事件

     

    2)键盘事件

     

    结语:

    1)前端和后台服务端搭配使用,除此之外无需任何配置,只需要打开后台服务端即可,前端设置后IP地址就可以直接访问

    2)可以控制图片压缩比例,默认30%,1600 *1280的分辨率出来的图片大小为130K左右,这个分辨率对对象清晰度影响不大

    3)可以控制帧流速,无操作动作时默认0.7秒发送一次屏幕信息,有交互时,不等待,连续发送

      

  • 相关阅读:
    三行Python代码查询IP
    剑指offer面试题29:数组中出现次数超过一半的数字
    【简】题解 AWSL090429 【数塔问题】
    Re.常系数齐次递推
    Re.多项式除法/取模
    【翻译】A simple stone game
    Re.多项式求逆
    Re.FFT
    题解 P4783 【【模板】矩阵求逆】
    关于win10企业版在极域电子教室软件 v4.0 2015 豪华版的全屏控制下如何取得自由
  • 原文地址:https://www.cnblogs.com/lanxiaoke/p/11721174.html
Copyright © 2011-2022 走看看