国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JS > 正文

Node.js 實現遠程桌面監控的方法步驟

2024-05-06 16:52:59
字體:
來源:轉載
供稿:網友

描述

最近使用node實現了一個遠程桌面監控的應用,分為服務端和客戶端,客戶端可以實時監控服務端的桌面,并且可以通過鼠標和鍵盤來控制服務端的桌面。

Node.js,遠程桌面監控

Node.js,遠程桌面監控

這里因為我是用的同一臺電腦,所以監控畫面是這樣的,當然使用兩臺電腦一個跑客戶端,一個跑服務端才有意義。

原理

其實這個應用的功能主要分為兩部分,一是實現監控,即在客戶端可以看到服務端的桌面,這部分功能是通過定時截圖來實現的,比如服務端一秒截幾次圖,然后通過socketio發送到客戶端,客戶端通過改變img的src來實現一幀幀的顯示最新的圖片,這樣就能看到動態的桌面了。監控就是這樣實現的。

另一個功能是控制,即客戶端對監控畫面的操作,包括鼠標和鍵盤的操作都可以在服務端的桌面真正的生效,這部分功能的實現是在electron的應用中監聽了所有的鼠標和鍵盤事件,比如keydown、keyup、keypress,mousedown、mouseup、mousemove、click等,然后通過socketio把事件傳遞到服務端,服務端通過 robot-js來執行不同的事件,這樣就能使得客戶端的事件在服務端觸發了。

實現

原理講完,我們來具體實現一下(源碼鏈接在這)。

實現socket通信

首先,服務端和客戶端分別引入socket.io和socket.io-client, 分別初始化

服務端:

const app = new Koa();const server = http.createServer(app.callback());createSocketIO(server);app.use((ctx): void => {  ctx.body = 'please connect use socket';});server.listen(port, (): void => {  console.log('server started at http://localhost:' + port);});//createSocketIOconst io = socketIO(server, {    pingInterval: 10000,    pingTimeout: 5000,    cookie: false  });io.on('connect', (socket): void => {  socket.emit('msg', 'connected');}

客戶端:

var socket = this.socket = io('http://' + this.ip + ':3000')socket.on('msg', (msg) => { console.log(msg)})socket.on('error', (err) => { alert('出錯了' + err)})

這樣,服務端和客戶端就通過socketio建立了鏈接。

實現桌面監控

之后我們首先要在服務端來截圖,使用screenshot-desktop這個包

const screenshot = require('screenshot-desktop')const SCREENSHOT_INTERVAL = 500;export const createScreenshot = (): Promise<[string, Buffer]> => {  return screenshot({format: 'png'}).then((img): [string, Buffer] => {    return [ img.toString('base64'), img];  }).catch((err): {} => {    console.log('截圖失敗', err);    return err;  })}export const startScreenshotTimer = (callback): {} => {  return setInterval((): void => {    createScreenshot().then(([imgStr, img]): void => {      callback(['data:image/png;base64,' + imgStr, img]);    })  }, SCREENSHOT_INTERVAL)}

然后通過socketio的emit來傳到客戶端:

startScreenshotTimer(([imgStr, img]): void => {  io.sockets.emit('screenshot', imgStr);});

客戶端收到圖片后,設置到img的src上(這里是base64的圖片url):

 <img   class="screenshot"   :src="screenshot"/>
data () { return {  screenshot: '' }}
socket.on('screenshot', (data) => { this.screenshot = data})

其實這樣就已經實現了桌面監控了,有興趣的同學可以照著這個思路實現看看,并不是很麻煩。

當然這樣的方案是有問題的,因為我們需要知道服務端桌面尺寸的大小,然后根據這個來調整客戶端顯示的圖片尺寸。

實現這個細節是使用的get-pixels這個庫,可以讀取本地圖片文件的寬度高度等信息,所以我先把圖片寫入本地,然后又讀取出來,這樣獲取到的屏幕尺寸。

interface ScreenSize {  width: number;  height: number;}function getScreenSize(img): Promise<ScreenSize> {  const imgPath = path.resolve(process.cwd(), './tmp.png');  fs.writeFileSync(imgPath, img);  return new Promise((resolve): void => {    getPixels(imgPath, function(err, pixels): void {      if(err) {        console.log("Bad image path")        return      }      resolve({        width: pixels.shape[0],        height: pixels.shape[1]      });    });  })}

然后通過socektio傳遞給客戶端

getScreenSize(img).then(({ width, height}) => {  io.sockets.emit('screensize', {    width,    height  })});

客戶端收到之后調整圖片大小就可以了

<img   class="screenshot"   :src="screenshot"  :style="screenshotStyle"/>
data () { return {  screenshot: '',  screenshotStyle: '', }}
socket.on('screensize', (screensize) => { this.screenshotStyle = {'width': screensize.width + 'px', 'height': screensize.height + 'px'}})

至此已經實現了桌面監控,并且圖片尺寸和服務端屏幕的尺寸是一致的。

這里還有一個細節,就是獲取到的圖片大小是物理像素,而客戶端設置的px是設備無關像素,也就是要除以dpr才是px的值。這里需要獲取dpr,因為目前只是在mac下用,所以直接除以2了。

實現遠程控制

代碼寫到這里,客戶端的electron應用中已經可以實時顯示服務端的桌面了。(當然像輸入ip的彈框,以及electron-vue和typescript等和主要邏輯無關的細節就不展開了。)

接下來我們要實現遠程控制,也就是監聽事件,傳遞事件,執行事件這幾部分。

首先我們定義一下傳遞的事件的格式:

interface MouseEvent {  type: string;  buttonType: string;  x: number;  y: number;}interface KeyboardEvent {  type: string;  keyCode: number;  keyName: string;}

鼠標事件MouseEvent,type為鼠標事件的類型,具體的值包括mousedown、mouseup、mousemove、click、dblclick,buttonType指的是鼠標的左鍵還是右鍵,值為 left 或 right,x和y是具體的坐標。

鍵盤事件KeyboardEvent,type為鍵盤事件的類型,具體的值包括keydown、keyup、keypress,keyCode為鍵盤碼,keyName為鍵的名字。

接下來我們要在客戶端監聽事件:

<img   class="screenshot"   :src="screenshot"  :style="screenshotStyle"  @mousedown="handleMouseEvent"  @mousemove="handleMouseEvent"   @mouseup="handleMouseEvent"  @click="handleMouseEvent"  @dblclick="handleMouseEvent"  />
window.onkeypress = window.onkeyup = window.onkeydown = this.handleKeyboardEvent

通過socekt把事件傳遞到服務端

 handleKeyboardEvent (e) {  this.socket && this.socket.emit('userevent', {   type: 'keyboard',   event: {    type: e.type,    keyName: e.key,    keyCode: e.keyCode   }  }) }, handleMouseEvent (e) {  this.socket && this.socket.emit('userevent', {   type: 'mouse',   event: {    type: e.type,    buttonType: e.buttons === 2 ? 'right' : 'left',    x: e.clientX,    y: e.clientY   }  }) },

然后在服務端把事件取出來執行,執行事件使用的是robot-js:

const { Mouse, Point, Keyboard } = require('robot-js');interface MouseEvent {  type: string;  buttonType: string;  x: number;  y: number;}interface KeyboardEvent {  type: string;  keyCode: number;  keyName: string;}export default class EventExecuter {  public mouse;  public keyboard;  public constructor(){    this.mouse = new Mouse();    this.keyboard = new Keyboard();  }  public executeKeyboardEvent(event: KeyboardEvent): void {    switch(event.type) {      case 'keydown':        this.keyboard.press(event.keyCode);        break;      case 'keyup':        this.keyboard.release(event.keyCode);        break;      case 'keypress':        this.keyboard.click(event.keyCode);        break;      default: break;    }  }  public executeMouseEvent(event): void {    Mouse.setPos(new Point(event.x, event.y));    const button = event.buttonType === 'left' ? 0 : 2    switch(event.type) {      case 'mousedown':        this.mouse.press(button);        break;      case 'mousemove':        break;      case 'mouseup':         this.mouse.release(button);        break;      case 'click':         this.mouse.click(button);        break;      case 'dblclick':         this.mouse.click(button);        this.mouse.click(button);        break;      default: break;    }  }  public exectue(eventInfo): void {    console.log(eventInfo);    switch (eventInfo.type) {      case 'keyboard':        this.executeKeyboardEvent(eventInfo.event);        break;      case 'mouse':        this.executeMouseEvent(eventInfo.event);        break;      default: break;    }  }}

至此,桌面監控和遠程控制的客戶端還有服務端的部分,以及兩端的通信都已經實現了。思路其實并不麻煩,但細節還是很多的。有興趣的同學可以把代碼下下來跑跑試試,或者按著這個思路自己實現一遍,還是挺好玩的。

源碼鏈接

remote-monitor-server

remote-monitor-client

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 武冈市| 通道| 赤壁市| 项城市| 老河口市| 泾川县| 犍为县| 襄垣县| 司法| 莱州市| 呼图壁县| 榆社县| 新田县| 青海省| 三门峡市| 贵南县| 贺兰县| 大厂| 专栏| 习水县| 宝应县| 马公市| 遵义县| 科技| 紫阳县| 芜湖县| 韶关市| 阳江市| 瓮安县| 西吉县| 镇远县| 秦安县| 永昌县| 岫岩| 皮山县| 南雄市| 民和| 长治县| 济阳县| 镇安县| 岳西县|