亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

no-vnc和node.js如何實現web遠程桌面

發布時間:2021-04-19 13:55:55 來源:億速云 閱讀:580 作者:小新 欄目:web開發

小編給大家分享一下no-vnc和node.js如何實現web遠程桌面,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

引言

項目需求,要求在瀏覽器端進行遠程桌面的訪問,如圖所示:

no-vnc和node.js如何實現web遠程桌面

實現遠程桌面,需要依賴VNC協議:

VNC(Virtual Network Computing),為一種使用RFB協議的屏幕畫面分享及遠程操作軟件。此軟件借由網絡,可發送鍵盤與鼠標的動作及即時的屏幕畫面。

no-vnc和node.js如何實現web遠程桌面

相關的參考比較少,去谷歌搜索出來的文章大多都是如何使用客戶端進行VNC的搭建與訪問,很少有將其內嵌到web里的,騰訊云有相關的功能,但因為業務安全性,咱也看不著人家咋實現的。

再見,百度。用百度查了一次之后,我才知道原來VNC是口紅。

no-vnc和node.js如何實現web遠程桌面

所以VNC實踐之路就是如下流程:

  1. 根據自己已有的知識與技能,設計一個VNC方案。

  2. 嘗試,分析可行性。

  3. 根據可行性修改方案細節,或推翻方案重新設計。

no-vnc和node.js如何實現web遠程桌面

從整體的最開始設計,到最終落地方案,大約經歷了以下七個方案的迭代:

  1. SpringBoot調用REALVNC的C++類庫,前后臺進行數據交互。失敗,因為REALVNC太貴了,客戶承受不起。

  2. SpringBoot中模仿TightVNC實現JavaViewer獲取數據,前后臺進行數據交互。失敗,因為TightVNC JavaViewer的源碼沒注釋,看不懂。

  3. SpringBoot中手寫VNC客戶端,前后臺數據交互。失敗,因為從0實現一個協議太復雜了,時間成本太高。

  4. 瀏覽器端只做VNC鏈接,使用原生客戶端,直接訪問主機。失敗,需要安裝軟件,且只能訪問局域網中的主機。

  5. 原生客戶端 + nginx數據轉發。失敗,需要安裝軟件,無法實現動態轉發(無法動態變更nginx配置文件)。

  6. no-vnc + nginx數據轉發。失敗,無法實現動態轉發(無法動態變更nginx配置文件)。

  7. no-vnc + node.js數據轉發。成功,完美實現。

實現

思想

整體思想如下圖所示:nginx轉發前臺的websocket連接,為了實現外網轉發,添加開發的node.js服務器作為代理,將瀏覽器端no-vnc的websocket數據報在運輸層轉發給目標主機。

no-vnc和node.js如何實現web遠程桌面

why nginx ?

如果思考過的話,其實發現不用nginx也能實現功能,這里使用nginx主要是減少了前臺對后臺架構的耦合。

添加網關轉發所有請求,對前臺只暴露一個端口,不管后臺用什么技術,用什么架構,用什么微服務,在前臺看來,就好像在訪問單體應用一樣。

就像目前的華軟項目一樣,后臺用了spring-boot、.net、node.js,各語言各框架發揮各自的優勢,通過nginx的轉發將各模塊連接起來,無論后臺的架構怎么變,對前臺毫無影響,這應該是微服務架構的最佳實踐。

no-vnc和node.js如何實現web遠程桌面

這是spring官方推薦的微服務架構圖,我們學習并實踐了api網關,spring推薦netflix zuul,我們用的nginx,在請求轉發上,二者性能不相上下。

隨著業務需求的增長,我們肯定也會服務拆分,服務注冊,服務發現,消息隊列,RPC調用。然后用上eureka、zookeeper、hystrix、feign等一個個優秀的開源組件,一起探索spring-cloud的最佳實踐。

websocket

之前一直不了解websocket,就是知道個名,具體細節沒有學習。

http協議:請求響應,客戶端請求,服務器響應,一次請求就結束。服務端無法主動向客戶端推送數據。

為了解決這個問題,websocket應運而生。如果所示,不做贅述。

no-vnc和node.js如何實現web遠程桌面

no-vnc

官網鏈接:noVNC

no-vnc和node.js如何實現web遠程桌面

安裝依賴:

npm install @novnc/novnc

前臺組件

一個空div,同時在組件中引用。

<div class="container" #container>
</div>
@ViewChild('container')
private container: ElementRef<HTMLDivElement>;

核心的代碼其實就這幾行,所有協議的細節都被封裝在no-vnc中的RFB類中了。

所有描述以訪問192.168.0.104主機的5900端口為例,websocket地址為:ws://127.0.0.1:8013/vnc/192.168.0.104:5900。

/**
 * VNC連接
 */
private VNCConnect(): void {
  /** 訪問 /vnc/ websocket */
  const url = `ws://${this.host}/vnc/${this.ip}:${this.port}`;

  /** 新建遠程控制對象 */
  this.rfb = new RFB(this.container.nativeElement, url, {
    credentials: {
      password: this.password,
    },
  });

  /** 添加connect事件監聽器 */
  this.rfb.addEventListener('connect', () => {
    this.rfb.focus();
  });
}

nginx 轉發

nginx監聽本地的8013端口。

ws://127.0.0.1:8013/vnc/192.168.0.104:5900請求發給了nginx,根據前綴匹配,以/vnc/開頭的轉發給8112端口。

location /vnc/ {
  proxy_pass http://127.0.0.1:8112/;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection $connection_upgrade;
}

node.js 轉發

node.js監聽8112端口,處理當前的websocket請求。

/** 建立基于 vnc_port 的 websocket 服務器 */
const vnc_server = http.createServer();
vnc_server.listen(vnc_port, function () {
  const web_socket_server = new WebSocketServer({server: vnc_server});
  web_socket_server.on('connection', web_socket_handler);
});

轉發的核心代碼在方法web_socket_handler中,以下是完整代碼:

這里說一句,之前寫的注釋都不規范,所有注釋都應該是文檔注釋,單行注釋使用/** 內容 */的格式。

/** 引入 http 包 */
const http = require('http');

/** 引入 net 包 */
const net = require('net');

/** 引入 websocket 類 */
const WebSocketServer = require('ws').Server;

/** 本機 ip 地址 */
const localhost = '127.0.0.1';

/** 開放的 vnc websocket 轉發端口 */
const vnc_port = '8112';

/** 打印提示信息 */
console.log(`成功創建 WebSocket 代理 : ${localhost} : ${vnc_port}`);

/** 建立基于 vnc_port 的 websocket 服務器 */
const vnc_server = http.createServer();
vnc_server.listen(vnc_port, function () {
  const web_socket_server = new WebSocketServer({server: vnc_server});
  web_socket_server.on('connection', web_socket_handler);
});

/** websocket 處理器 */
const web_socket_handler = function (client, req) {
  /** 獲取請求url */
  const url = req.url;

  /** 截取主機地址 */
  const host = url.substring(url.indexOf('/') + 1, url.indexOf(':'));

  /** 截取端口號 */
  const port = Number(url.substring(url.indexOf(':') + 1));

  /** 打印日志 */
  console.log(`WebSocket 連接 : 版本 ${client.protocolVersion}, 協議 ${client.protocol}`);

  /** 連接到 VNC Server */
  const target = net.createConnection(port, host, function () {
    console.log('連接至目標主機');
  });

  /** 數據事件 */
  target.on('data', function (data) {
    try {
      client.send(data);
    } catch (error) {
      console.log('客戶端已關閉,清理到目標主機的連接');
      target.end();
    }
  });

  /** 結束事件 */
  target.on('end', function () {
    console.log('目標主機已關閉');
    client.close();
  });

  /** 錯誤事件 */
  target.on('error', function () {
    console.log('目標主機連接錯誤');
    target.end();
    client.close();
  });

  /** 消息事件 */
  client.on('message', function (msg) {
    target.write(msg);
  });

  /** 關閉事件 */
  client.on('close', function (code, reason) {
    console.log(`WebSocket 客戶端斷開連接:$[code] [${reason}]`);
    target.end();
  });

  /** 錯誤事件 */
  client.on('error', function (error) {
    console.log(`WebSocket 客戶端出錯:${error}`);
    target.end();
  });
};

以上是“no-vnc和node.js如何實現web遠程桌面”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

呼伦贝尔市| 陇川县| 保山市| 伊吾县| 昔阳县| 栾川县| 临武县| 绥中县| 丰镇市| 夏河县| 鲁山县| 日照市| 大名县| 周宁县| 巴里| 吉林市| 修文县| 汝州市| 新丰县| 四子王旗| 五华县| 红安县| 博罗县| 烟台市| 庆阳市| 赤峰市| 青州市| 新泰市| 崇仁县| 安徽省| 永丰县| 张家港市| 宁城县| 若羌县| 靖西县| 芦溪县| 文水县| 鲁甸县| 辉南县| 庆云县| 晋宁县|