日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java實(shí)現(xiàn)遠(yuǎn)程屏幕監(jiān)視

遠(yuǎn)程屏幕監(jiān)視使得控制方可以在遠(yuǎn)程主機(jī)上監(jiān)視其它一臺機(jī)器,其主要實(shí)現(xiàn)原理就是將被控制機(jī)器的屏幕作為圖片傳送給監(jiān)視方,在Java中要實(shí)現(xiàn)遠(yuǎn)程屏幕監(jiān)視,主要解決以下幾個(gè)問題即可:

1:將當(dāng)前屏幕的顯示內(nèi)容捕捉為圖片

2:將捕捉的圖片發(fā)送到遠(yuǎn)程控制主機(jī)

3:遠(yuǎn)程控制主機(jī)接收到在本地顯示

4:利用多線程重復(fù)上面三步達(dá)到實(shí)時(shí)更新

說起來怎么這么簡單啊,今天試著做了一下遠(yuǎn)程屏幕監(jiān)視的實(shí)驗(yàn),發(fā)現(xiàn)還真不是這么簡單的,把我的心得總結(jié)出來共享一下,希望對你有用。

將當(dāng)前屏幕顯示內(nèi)容捕捉為圖片

Java代碼

 
 
 
 
  1. Robot robot = new Robot();   
  2. //要捕捉的屏幕顯示范圍,下面以全屏示例說明   
  3. Rectangle rect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());   
  4. BufferedImage bm = robot.createScreenCapture(rect);  

通過上面幾行代碼就把屏幕的當(dāng)前顯示內(nèi)容保存為內(nèi)存中的BufferedImage對象,這個(gè)確實(shí)簡單.

將捕捉的圖片發(fā)送到遠(yuǎn)程控制主機(jī)

要達(dá)到實(shí)時(shí)監(jiān)控,怎么保證發(fā)送效率,在網(wǎng)絡(luò)狀況不良好時(shí)怎么保證發(fā)送時(shí)使用帶寬

因?yàn)橐煌5赝刂茩C(jī)上發(fā)送圖片,所以傳送的圖片不能太大,否則會(huì)影響實(shí)時(shí)性,當(dāng)網(wǎng)絡(luò)狀況不好時(shí),占用帶寬過多則更加會(huì)給實(shí)時(shí)性帶來嚴(yán)峻的考驗(yàn),解決的方法有兩個(gè):

1:使用jpg格式的圖片進(jìn)行傳輸。

jpg是一種支持高度壓縮技術(shù)的圖片格式,它所存儲的信息不包含透明度,同等質(zhì)量的情形下相對來說比png,gif等格式的圖片要小很多,當(dāng)然,文件大小是以圖像質(zhì)量為代價(jià)的,如果你一味地追求壓縮后的大小,圖像質(zhì)量就會(huì)受損了。我在實(shí)驗(yàn)中使用大小為28394字節(jié)的png圖片經(jīng)過jpg壓縮后大小僅剩5815字節(jié)(不是PS,整個(gè)過程全部使用Java完成)。

2:將用圖片生成的字節(jié)數(shù)據(jù)先壓縮再傳送。

這一步是仁者見仁,智者見智了,有人說沒有必要,jgp格式的圖片再壓縮也小不了多少。確實(shí)是這樣的,我在實(shí)驗(yàn)中把5815字節(jié)大小的jpg經(jīng)過zip壓縮后為大小變?yōu)?702,有點(diǎn)小作用,實(shí)際應(yīng)用中壓縮與否就看你了(壓縮其它格式的圖片效果可能會(huì)明顯一點(diǎn),我在實(shí)驗(yàn)中把一個(gè)大小為883078字節(jié)的bmp圖片壓縮后大小僅為16849字節(jié),很可觀,達(dá)到了52:1)。

我能想到的就是這兩點(diǎn)了,歡迎各位仁智雙全的人補(bǔ)充。下面就是這兩點(diǎn)用到的Java技術(shù),Java高手就直接跳過吧。

使用Java將圖片處理成jpg格式

Java代碼

 
 
 
 
  1. //outputstream就是要寫入處理后的jpg圖片的輸出流,要保存到文件的話就用FileOutputStream   
  2. JPEGCodec.createJPEGEncoder(outputstream).encode(bm);   
  3. ImageIO.write(bm, "jpg", outputstream);  

這兩種方法有什么差別呢?別的我不知道,就平均效率來說,第二種是第一種的2倍,我實(shí)驗(yàn)中轉(zhuǎn)換了10次,使用的時(shí)間分別是125和250(單位是百分之一毫秒,機(jī)子有點(diǎn)慢的說).

把圖片數(shù)據(jù)轉(zhuǎn)換為字節(jié)數(shù)組

Java代碼

 
 
 
 
  1. ByteArrayOutputStream bos = new ByteArrayOutputStream();   
  2. JPEGCodec.createJPEGEncoder(bos).encode(bm);   
  3. // 上句也可以用 ImageIO.write(bm, "jpg", bos)實(shí)現(xiàn)   
  4. bos.flush();   
  5. byte[] data = bos.toByteArray();  

將生成的字節(jié)數(shù)組進(jìn)行zip壓縮

Java代碼

 
 
 
 
  1. ZipOutputStream zos = new ZipOutputStream(bos);   
  2. zos.setLevel(Deflater.BEST_COMPRESSION);   
  3. //下面我以ScreenCapture.jpg說明   
  4. zos.putNextEntry(new ZipEntry("ScreenCapture.jpg"));   
  5. zos.write(data);   
  6. zos.closeEntry();  

好了,這個(gè)時(shí)候就可以把字節(jié)數(shù)組發(fā)往監(jiān)控機(jī)器了,如果你發(fā)了,你就知道,問題又來了(不會(huì)吧!)。

1:既然是采用多線程發(fā)送多張圖片,那么對于一張圖片,接收方怎么知道你發(fā)完了呢?

2:如果要發(fā)其它的數(shù)據(jù),比如鼠標(biāo)點(diǎn)擊等,接收方又怎么區(qū)分什么時(shí)候發(fā)的是圖片,什么時(shí)候發(fā)的是其它的……

對于這兩點(diǎn)問題,最直接的解決方法是當(dāng)數(shù)據(jù)發(fā)送完成后關(guān)閉發(fā)送字節(jié)的輸出流,第二次發(fā)送時(shí)重新建立連接(網(wǎng)上確實(shí)有人這樣肆無忌憚地做),這種方法采用不采用就看良心了(汗)。我采用的解決方法是,每次發(fā)送數(shù)據(jù)前都告訴接收方要發(fā)什么東西(解決問題2),同時(shí)告訴它我發(fā)了多少字節(jié)(解決問題1),接收方只要接收了這么多字節(jié)數(shù),就表示本次發(fā)送完成,最后再發(fā)送真正要發(fā)送的內(nèi)容(圖片等),說簡單點(diǎn)就是,發(fā)送的消息結(jié)構(gòu)如下:

【標(biāo)識位 大小 消息】

標(biāo)識位:采用一個(gè)整型,其實(shí)是一個(gè)byte,占一個(gè)字節(jié)

大小:一個(gè)整型,占四個(gè)字節(jié)

消息:實(shí)際要發(fā)送的字節(jié)數(shù)組,長度就是字節(jié)數(shù)組的長度

這樣接收方每次都是先讀取一個(gè)整數(shù),判斷發(fā)送方是要發(fā)送什么消息,然后再判斷消息的大小,然后再接收指定大小的消息,最后完成本次發(fā)送轉(zhuǎn)入下一次接收工作。

采用Socket的方式進(jìn)行消息的發(fā)送

Java代碼

 
 
 
 
  1. DataOutputStream dos = new DataOutputStream(client.getOutputStream());   
  2. //SEND_IMAGE_SYMBOL是一個(gè)標(biāo)識位,你隨便定義,只要保證能與其它標(biāo)識位區(qū)分就行   
  3. dos.write(SEND_IMAGE_SYMBOL);   
  4.   
  5. dos.writeInt(data.length);   
  6. dos.write(data);   
  7. dos.flush();  

啊,真不容易,終于發(fā)送出去了!不知道那邊接收到了沒有?那現(xiàn)在就去追蹤報(bào)道吧。

遠(yuǎn)程控制主機(jī)接收消息

Java代碼

 
 
 
 
  1. //先要判斷消息的類型   
  2.  DataInputStream reader = new DataInputStream(socket.getInputStream());   
  3.  int msgSymbol = reader.read();   
  4.  //還記得這個(gè)SEND_IMAGE_SYMBOL嗎   
  5.  if (msgSymbol == SEND_IMAGE_SYMBOL)   
  6.  {   
  7.      //哦,是要發(fā)送圖片啊。讓我看看你的圖片有多大   
  8.      int msgSize = reader.readInt();   
  9.     
  10.     //暈,你網(wǎng)速好也不用發(fā)這么大吧,我一次接收不完的,不過幸好我有準(zhǔn)備   
  11.     byte[] buffer = new byte[msgSize];   
  12.     int length = 0;   
  13.   
  14.     while (length < msgSize)   
  15.     {   
  16.         int readSize = reader.read(buffer, length, msgSize - length);   
  17.   
  18.         if (readSize > 0)   
  19.         {   
  20.             length = length + readSize;   
  21.         }   
  22.         else  
  23.         {   
  24.             break;   
  25.         }   
  26.     }   
  27.     //這是非常關(guān)鍵的,圖片太大時(shí)一次性是讀不完的,一定要使用緩沖重復(fù)讀取。   
  28.   
  29.     //人家給我發(fā)送的消息是圖片,怎么把字節(jié)數(shù)組還原成圖片呢?   
  30.     ByteArrayInputStream bis = new ByteArrayInputStream(buffer);   
  31.     ZipInputStream zis = new ZipInputStream(bis);   
  32.     //讀取壓縮的數(shù)據(jù)內(nèi)容。   
  33.     ZipEntry ze = zis.getNextEntry();   
  34.     BufferedImage bi = ImageIO.read(zis);   
  35.     //或者BufferedImage bi = JPEGCodec.createJPEGDecoder(zis).decodeAsBufferedImage();   
  36.     //上面兩行代碼的差別已經(jīng)說過了   
  37.     //另外,如果在發(fā)送的時(shí)候你沒有進(jìn)行壓縮,把上面的zis換成bis就行。   
  38.   
  39.   
  40.     //有了BufferedImage對象,剩下的就是把它顯示出來了進(jìn)行遠(yuǎn)程"偷窺",任何一個(gè)支持圖片顯示的swing組件你都以用,我在實(shí)驗(yàn)中用的是JPanel,一個(gè)簡單又支持雙緩沖的組件。   
  41. }  

最后,就是使用多線程重復(fù)上面的步驟進(jìn)行實(shí)時(shí)監(jiān)控了。有什么問題歡迎指正。

本次實(shí)驗(yàn)進(jìn)行的還算成功,成功偷窺了自己的桌面。謝謝你堅(jiān)持看完我的文章,向你致敬!


文章名稱:Java實(shí)現(xiàn)遠(yuǎn)程屏幕監(jiān)視
URL地址:http://www.dlmjj.cn/article/dpegoho.html