自己动手实现网页版的远程桌面

这篇具有很好参考价值的文章主要介绍了自己动手实现网页版的远程桌面。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

因为一些原因,小编需要使用远程桌面软件,但小编实在穷,所以使用的是免费版的向日葵。就在前几天,免费版的向日葵莫名其妙崩了(各种重启都没用),虽然之后通过升级这种高级手段又重新可以用了,但是这在我幼小的心灵上留下了创伤,所以,我决定自己手写一个远程桌面WEB版。不过最后因为时间有限,我写了个demo出来,以后有时间再完善吧。这次,我把自己的思路放出来供大家参考。

实现原理

截取当前屏幕,并通过websocket将其发到Web端展示,Web端编写鼠标、键盘事件,通过WebSocket发送到服务端处理。

服务端

服务端使用了WPF进行开发,websocket用了第三方库WebSocketSharpFork来实现。

接下来,上代码:

WebSocket处理数据

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WebSocketSharp;
using WebSocketSharp.Server;

namespace RemoteApp
{
    public class Echo : WebSocketBehavior
    {
        private bool isClose = false;

        protected override void OnClose(CloseEventArgs e)
        {
            isClose = true;
            Trace.WriteLine("Closed...");
        }

        protected override void OnMessage(MessageEventArgs e)
        {
            Trace.WriteLine(e.Data);
            HandleData(e.Data);
        }

        protected override void OnOpen()
        {
            Trace.WriteLine("Open...");
            //Sessions.Broadcast("Open...");

            Thread thread = new Thread(UpdateDesktop);
            thread.Start();
        }

        private void UpdateDesktop()
        {
            while (true)
            {
                if (isClose) return;
                Bitmap bitmap = GetBitmapFromScreen();
                Sessions.Broadcast(BitmapToByte(bitmap));
            }
        }

        private void HandleData(string data)
        {
            try
            {
                JObject item = (JObject)JsonConvert.DeserializeObject(data);
                int type = Int32.Parse(item["type"].ToString());
                byte keyCode;
                int x, y;
                switch (type)
                {
                    // Key Down
                    case 0:
                        keyCode = byte.Parse(item["key"].ToString());
                        KeyBoard.keyDown(keyCode);
                        break;
                    // Key Up
                    case 1:
                        keyCode = byte.Parse(item["key"].ToString());
                        KeyBoard.keyUp(keyCode);
                        break;
                    // Mouse move
                    case 2:
                        x = Convert.ToInt32(Convert.ToDouble(item["x"].ToString()));
                        y = Convert.ToInt32(Convert.ToDouble(item["y"].ToString()));
                        MouseFlag.SetCursorPos(x, y);
                        break;
                    // Mouse Left Click
                    case 3:
                        x = Convert.ToInt32(Convert.ToDouble(item["x"].ToString()));
                        y = Convert.ToInt32(Convert.ToDouble(item["y"].ToString()));
                        MouseFlag.MouseLeftClickEvent(x, y, 0);
                        break;
                    // Mouse Right Click
                    case 4:
                        x = Convert.ToInt32(Convert.ToDouble(item["x"].ToString()));
                        y = Convert.ToInt32(Convert.ToDouble(item["y"].ToString()));
                        MouseFlag.MouseRightClickEvent(x, y, 0);
                        break;
                    // Mouse Left Down
                    case 5:
                        x = Convert.ToInt32(Convert.ToDouble(item["x"].ToString()));
                        y = Convert.ToInt32(Convert.ToDouble(item["y"].ToString()));
                        MouseFlag.MouseLeftDownEvent(x, y, 0);
                        break;
                    // Mouse Left Up
                    case 6:
                        x = Convert.ToInt32(Convert.ToDouble(item["x"].ToString()));
                        y = Convert.ToInt32(Convert.ToDouble(item["y"].ToString()));
                        MouseFlag.MouseLeftUpEvent(x, y, 0);
                        break;
                    // Mouse Wheel
                    case 7:
                        x = Convert.ToInt32(Convert.ToDouble(item["x"].ToString()));
                        y = Convert.ToInt32(Convert.ToDouble(item["y"].ToString()));
                        var d = Convert.ToInt32(Convert.ToDouble(item["deltaY"].ToString())) * Convert.ToInt32(Convert.ToDouble(item["deltaFactor"].ToString()));
                        MouseFlag.MouseWheelEvent(x, y, d);
                        break;

                }
            }
            catch(Exception e)
            {

            }
        }

        private Bitmap GetBitmapFromScreen()
        {

            System.Drawing.Rectangle rc = System.Windows.Forms.SystemInformation.VirtualScreen;
            var bitmap = new Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CopyFromScreen(rc.X, rc.Y, 0, 0, rc.Size, System.Drawing.CopyPixelOperation.SourceCopy);
            }

            return bitmap;
        }

        private Byte[] BitmapToByte(Bitmap bitmap)
        {
            MemoryStream stream = new MemoryStream();
            bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
            Byte[] buffer = new Byte[stream.Length];
            stream.Seek(0, SeekOrigin.Begin);
            stream.Read(buffer, 0, Convert.ToInt32(stream.Length));
            return buffer;
        }

    }
}

开启WebSocket

private void OpenWebSocketServer()
{
    server = new WebSocketServer(int.Parse(PortName.Text));

    server.AddWebSocketService<Echo>("/Echo");
    server.Start();

}

客户端

Web端随便用了HTML写了一下,大家参考一下就行

<html>
    <head>
        <title>Remote</title>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery-mousewheel/3.1.9/jquery.mousewheel.min.js"></script>
    </head>
    <script>
         	var ws;
            var isEnter = false;
            var remoteWidth = 1920;
            var remoteHeight = 1080;
            var widthRadio = remoteWidth / 1000;
            var heightRadio = remoteHeight / 600;

            function OpenWS() {
                initWS();
                initEvent();
            }

            function initWS() {
                ws = new WebSocket("ws://192.168.1.105:10086/Echo");
                ws.onopen = function () {
                    console.log("Openened connection to websocket");

                };
                ws.onclose = function () {
                    console.log("Close connection to websocket");
                    
                    // 断线重连
                    initWS();
                }

                ws.onmessage = function (e) {
                    // console.log(e.data)
                    var blob = new Blob([e.data], { type: "image/jpg" });
                    var url = URL.createObjectURL(blob);
                    var image = document.getElementById("desktop");
                    image.src = url;
                }
            }

            function initEvent(){

                //禁用文本选择
                document.onselectstart = function(e){
                    e = window.event || e;
                    if(window.event){
                        try{e.keyCode = 0;}catch(e){}
                        e.returnValue = false;
                    }else{
                        e.preventDefault();
                    }
                };
                
                //禁用右键菜单
                $(document).contextmenu(function(e){
                    e = window.event || e;

                    if(isEnter)
                        sendRightClick(e.offsetX * widthRadio, e.offsetY * heightRadio, 1);

                    if(window.event){
                        try{e.keyCode = 0;}catch(e){}
                        e.returnValue = false;
                    }else{
                        e.preventDefault();
                    }
                });

                $(document).keydown(function (e) {
                    e = window.event || e;
                    var keycode = e.keyCode || e.which
                    // console.log('Down' + e.keyCode);
                    if(isEnter)
                        sendKeyDown(keycode);
                    if(e.ctrlKey || e.altKey || e.shiftKey || (keycode > 111 && keycode <124)){
                        if(window.event){
                            try{e.keyCode = 0;}catch(e){}
                            e.returnValue = false;
                        }else{
                            e.preventDefault();
                        }
                        // window.event.returnValue = false;
                    }

                });

                $(document).keyup(function(e) {
                    var keycode = e.keyCode || e.which
                    // console.log('up' + e.keyCode);
                    if(isEnter)
                        sendKeyUp(keycode)
                });

                $(document).mousemove(function(e) {
                    if(isEnter)
                        sendMouseMove(e.offsetX * widthRadio, e.offsetY * heightRadio);
                });

                $(document).click(function(e) { 
                    console.log('click');
                    if(isEnter)
                        sendLeftClick(e.offsetX * widthRadio, e.offsetY * heightRadio);
                });

                $(document).mousedown(function(e){
                    // console.log('mouse down');
                    if(isEnter)
                    sendMouseLeftDown(e.offsetX * widthRadio, e.offsetY * heightRadio);
                });

                $(document).mouseup(function(e) {
                    // console.log('mouse up');
                    if(isEnter)
                        sendMouseLeftUp(e.offsetX * widthRadio, e.offsetY * heightRadio);
                });

                $(window).mousewheel(function(e) {
                    // console.log(e);
                    sendMouseWheel(e.offsetX * widthRadio, e.offsetY * heightRadio, e.deltaY, e.deltaFactor);
                });
                
            }

            function sendKeyDown(keyCode){
                ws.send("{'type':0, 'key':" + keyCode + "}")
            }
            
            function sendKeyUp(keyCode){
                ws.send("{'type':1, 'key':" + keyCode + "}")
            }

            function sendMouseMove(dx, dy){
                ws.send("{'type':2, 'x':" + dx + ", 'y':" + dy +"}");
            }

            function sendLeftClick(dx, dy){
                ws.send("{'type':3, 'x':" + dx + ", 'y':" + dy + "}");
            }
            
            function sendRightClick(dx, dy){
                ws.send("{'type':4, 'x':" + dx + ", 'y':" + dy + "}");
            }

            function sendMouseLeftDown(dx, dy){
                ws.send("{'type':5, 'x':" + dx + ", 'y':" + dy + "}");
            }
            
            function sendMouseLeftUp(dx, dy){
                ws.send("{'type':6, 'x':" + dx + ", 'y':" + dy + "}");
            }

            function sendMouseWheel(dx, dy, deltaY, deltaFactor) {
                ws.send("{'type':7, 'x':" + dx + ", 'y':" + dy + ", 'deltaY':" + deltaY + ", 'deltaFactor':" + deltaFactor + "}");

            }

            function imgMouseEnter(){
                isEnter = true;
            }

            function imgMouseLeave(){
                isEnter = false;
            }

    </script>
    <body>
        <button onclick="OpenWS()">打开WebSocket</button>
        <img id="desktop" width="1000" height="600" draggable="false" onmouseenter="imgMouseEnter()" onmouseleave="imgMouseLeave()"/>
    </body>
</html>

展示图片

自己动手实现网页版的远程桌面

服务端界面

自己动手实现网页版的远程桌面

Web端界面

最后

界面随便写写的,代码我放GitHub上了,有兴趣的自己去看
代码:远程桌面Web版文章来源地址https://www.toymoban.com/news/detail-413349.html

到了这里,关于自己动手实现网页版的远程桌面的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 详解自己动手添加一个函数实现任意字段调用

    是否遇到过想调用某些自定义字段,却发现dedecms的标签底层模板字段不包括这个字段呢?这就大大限制了灵活性,但dede也不可能让所有字段都允许调用的,那样就会大大降低系统效率,所以今天分享的是一个比较完美解决这个问题的方法,配合dede标签,几乎可以说没有什么

    2024年02月02日
    浏览(10)
  • 17游刃有余:动手实现自己的RPC框架(三)

    这篇文章我们来实现跨语言的网络通信。 跨语言RPC框架的必要性主要体现在以下几个方面: 解决不同语言之间的互操作性。不同语言使用的数据类型和序列化方式可能不同,跨语言 RPC 框架可以提供通用的编解码库和语言适配器,以便将不同语言的数据转换为通用的格式进行

    2024年02月14日
    浏览(10)
  • 自己动手实现一个深度学习算法——三、神经网络的学习

    自己动手实现一个深度学习算法——三、神经网络的学习

    这里所说的“学习”是指从训练数据中自动获取最优权重参数的过程 。为了使神经网络能进行学习,将导入 损失函数 这一指标。而学习的目的就是以该损失函数为基准,找出能使它的值达到最小的权重参数。为了找出尽可能小的损失函数的值,利用了 函数斜率的梯度法 。

    2024年02月05日
    浏览(11)
  • 自己动手写数据库系统:实现一个小型SQL解释器(中)

    我们接上节内容继续完成SQL解释器的代码解析工作。下面我们实现对update语句的解析,其语法如下: UpdateCmd - INSERT | DELETE | MODIFY | CREATE Create - CreateTable | CreateView | CreateIndex Insert - INSERT INTO ID LEFT_PARAS FieldList RIGHT_PARAS VALUES LEFT_PARS ConstList RIGHT_PARAS FieldList - Field ( COMMA FieldList)?

    2024年02月12日
    浏览(10)
  • 自己动手写编译器:使用 PDA 实现增强和属性语法的解析

    自己动手写编译器:使用 PDA 实现增强和属性语法的解析

    在前面章节中我们了解了增强语法和属性语法,特别是看到了这两种语法的结合体,本节我们看看如何使用前面我们说过的自顶向下自动机来实现这两种语法结合体的解析,这里使用的方法也是成熟编译器常用的一种语法解析算法。 首先我们先给出上一节给出的混合语法:

    2024年02月20日
    浏览(9)
  • 自己动手封装axios通用方法并上传至私有npm仓库:详细步骤与实现指南

    自己动手封装axios通用方法并上传至私有npm仓库:详细步骤与实现指南

    一、构建方法 确定工具库的需求和功能:在开始构建工具库之前,你需要明确你的工具库需要包含哪些方法及工具,以及这些工具或方法应该具备哪些功能。这有助于你更好地规划你的开发工作。 编写工具代码:使用你熟悉的前端框架(如React、Vue等)编写工具代码。确保你

    2024年04月14日
    浏览(23)
  • javascript实现网页背景音乐自动播放

    在HTML文档中添加一个标签,指定音乐文件路径和自动播放属性。 在JavaScript中获取该元素,设置其音量为0(静音)或一个合适的值。 在网页加载完毕后,调用元素的play()方法,开始播放音乐。 完整代码如下: 注意:自动播放可能会受到浏览器限制,需要用户允许浏览器自动

    2024年02月04日
    浏览(11)
  • VScode网页版的使用

    VScode网页版的使用

    VScode网页版的使用 点击进入网页版的编辑器的使用:https://vscode.dev/ 可进行自我git-hub的账号的登录使用,实现随时随地编程; 可通过该地址进行连接git-hub的项目,但不适应于编写与提交代码,可用于阅读他人的代码; 例如用于阅读vue的源码,或他人的代码等: 在原本项目

    2024年02月12日
    浏览(10)
  • Qt推流程序(视频文件/视频流/摄像头/桌面转成流媒体rtmp+hls+webrtc)可在网页和播放器远程观看

    Qt推流程序(视频文件/视频流/摄像头/桌面转成流媒体rtmp+hls+webrtc)可在网页和播放器远程观看

    推流直播就是把采集阶段封包好的内容传输到服务器的过程。其实就是将现场的视频信号从手机端,电脑端,摄影机端打包传到服务器的过程。“推流”对网络要求比较高,如果网络不稳定,直播效果就会很差,观众观看直播时就会发生卡顿等现象,观看体验比较糟糕。主流

    2024年02月04日
    浏览(37)
  • 统信UOS桌面操作系统教育版的安装方法

    统信UOS桌面操作系统教育版的安装方法

    原文链接:统信UOS桌面操作系统教育版的安装方法 hello,大家好!继我们之前详细介绍了统信UOS桌面操作系统的专业版、服务器版以及家庭版安装方法之后,今天我将带大家了解如何安装统信UOS的教育版,使用的是最新的1060镜像。 统信UOS教育版是专为教育环境设计的操作系

    2024年01月20日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包