Java實(shí)現(xiàn)遠(yuǎn)程控制技術(shù)完整源代碼分享
Java實(shí)現(xiàn)遠(yuǎn)程控制技術(shù)
java自帶的java.net.和java.awt.robot. 的混合可以用于實(shí)現(xiàn)通過網(wǎng)絡(luò)對(duì)另一臺(tái)計(jì)算機(jī)的遠(yuǎn)程控制,其中包括控制遠(yuǎn)程計(jì)算機(jī)鼠標(biāo)的動(dòng)作和鍵盤的輸入,以及實(shí)時(shí)獲得遠(yuǎn)程計(jì)算機(jī)屏幕的圖像。本文將用簡潔的語言和由淺入深的邏輯,教大家如何掌握這個(gè)技術(shù)。
首先先看一下效果圖:
遠(yuǎn)程端計(jì)算機(jī)界面:
控制端計(jì)算機(jī)界面:
控制端輸入:
遠(yuǎn)程端輸入:
一下開始詳細(xì)介紹遠(yuǎn)程控制的技術(shù)思路。
首先兩臺(tái)計(jì)算機(jī)通過java.net的Socket來進(jìn)行連接。
一端先打開一個(gè)ServerSocket,然后另外一端用socket進(jìn)行連接。
服務(wù)器端
應(yīng)該設(shè)置一個(gè)ServerSocket,并且初始化需要用到的輸入輸出流:
public static void OpenServer() throws IOException, ClassNotFoundException{ System.out.println("ServerStart....."); ServerSocket server = new ServerSocket(7777); socket = server.accept(); System.out.println("連接上...\n"+socket); OIS = new ObjectInputStream(socket.getInputStream()); OOS=new ObjectOutputStream(socket.getOutputStream()); }
客戶機(jī)端
應(yīng)該用socket去連接服務(wù)器,并且初始化輸入輸出流:
public static void StartConnection(String IP,int port) throws UnknownHostException, IOException, AWTException{ socket = new Socket("192.168.0.106",7777); if(socket.isConnected()){ System.out.println("socket connected..."+socket); } OOS = new ObjectOutputStream(socket.getOutputStream()); OIS = new ObjectInputStream(socket.getInputStream()); }
這樣兩臺(tái)計(jì)算機(jī)就鏈接在一起并且可以通過流(InputStream和OutputStream)來交換數(shù)據(jù)了
接下來大家可以想一想,要實(shí)現(xiàn)遠(yuǎn)程控制的兩臺(tái)計(jì)算機(jī)需要交換什么信息呢?首先被控制端需要不斷向控制端提供截取的屏幕圖像(這個(gè)我們將會(huì)用java.awt.robot來實(shí)現(xiàn)),然后鼠標(biāo)和鍵盤根據(jù)控制端傳來的事件(inputEvent)來做出相同的操作(用robot來實(shí)現(xiàn))。然后控制端當(dāng)然首先要接收被控制端傳來的圖像并且反映到一個(gè)面板上(pane),然后監(jiān)聽本機(jī)上鍵盤鼠標(biāo)的動(dòng)作再傳給被控制端的主機(jī)(我們通過在面板pane上設(shè)置一個(gè)監(jiān)聽器listener來實(shí)現(xiàn))
這里遇到的一個(gè)問題就是用于傳送的圖片無論是用image還是用bufferedImage都是不可串行化的。所以不能用I/OStream進(jìn)行傳送,所以為了解決這個(gè)問題,我們需要把圖像數(shù)據(jù)封裝在一個(gè)類里面并implements Serializable接口
圖像類如下:
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Serializable; public class Message implements Serializable { private static final long serialVersionUID = 1L; private String fileName; // 文件名稱 private long fileLength; // 文件長度 private byte[] fileContent; // 文件內(nèi)容 public Message(){ } public Message(String filePath) throws IOException{ File file = new File(filePath); this.fileLength=file.length(); this.fileName=file.getName(); FileInputStream FIS = new FileInputStream(filePath); byte[] bytes = new byte[(int)fileLength]; FIS.read(bytes,0,(int)fileLength); this.fileContent=bytes; } public String getFileName() { return fileName;} public void setFileName(String fileName) { this.fileName = fileName;} public long getFileLength() { return fileLength; } public void setFileLength(long fileLength) {this.fileLength = fileLength;} public byte[] getFileContent() {return fileContent;} public void setFileContent(byte[] fileContent) {this.fileContent = fileContent;} }
這樣就可以實(shí)現(xiàn)圖像通過ObjectInputStream和ObjectOutputStream的串行化傳播了
了解了以上基礎(chǔ)之后首先我們要完成控制端的UI界面設(shè)置,圖片接收,和鍵盤鼠標(biāo)動(dòng)作監(jiān)聽:
首先是設(shè)置接收?qǐng)D片:
public static void reveivePic() throws ClassNotFoundException, IOException{ Message g = (Message)OIS.readObject(); FileOutputStream FOS = new FileOutputStream("D:\\OUT\\"+g.getFileName()); FOS.write(g.getFileContent(),0,(int)g.getFileLength()); FOS.flush(); FileInputStream FIS= new FileInputStream("D:\\OUT\\"+g.getFileName()); BufferedImage BI = ImageIO.read(FIS); IIC=new ImageIcon(BI); Image img = IIC.getImage(); Toolkit tk = Toolkit.getDefaultToolkit() ; Dimension d =tk.getScreenSize(); int w = d.width; int h =d.height; BufferedImage bi = resize(img,800,600); imag_lab.setIcon(new ImageIcon(bi)); imag_lab.repaint();//銷掉以前畫的背景 } private static BufferedImage resize(Image img, int newW, int newH) { int w = img.getWidth(null); int h = img.getHeight(null); BufferedImage dimg = new BufferedImage(newW, newH,BufferedImage.TYPE_INT_BGR); Graphics2D g = dimg.createGraphics(); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null); g.dispose(); return dimg; }
這樣接收了來自O(shè)bjectInputStream的Message類之后就可以把圖片重新設(shè)置到面板pane的大小然后展示出來
下一步就是設(shè)置面板屬性和監(jiān)聽器:
public static void showUI(){ //控制臺(tái)標(biāo)題 JFrame jf = new JFrame("控制臺(tái)");setListener(jf); //控制臺(tái)大小 jf.setSize(500, 400); //imag_lab用于存放畫面 imag_lab = new JLabel(); jf.add(imag_lab); //設(shè)置控制臺(tái)可見 jf.setVisible(true); //控制臺(tái)置頂 jf.setAlwaysOnTop(true); jf.setResizable(true); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
監(jiān)聽器:
public static void setListener( JFrame frame){ //panel設(shè)置監(jiān)聽器 frame.addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent e) { sendEventObject(e); } @Override public void keyReleased(KeyEvent e) { sendEventObject(e); } @Override public void keyTyped(KeyEvent e) { } }); frame.addMouseWheelListener(new MouseWheelListener(){ public void mouseWheelMoved(MouseWheelEvent e) { sendEventObject(e); } }); frame.addMouseMotionListener(new MouseMotionListener(){ public void mouseDragged(MouseEvent e) { sendEventObject(e); } public void mouseMoved(MouseEvent e) { sendEventObject(e); } }); frame.addMouseListener(new MouseListener(){ public void mouseClicked(MouseEvent e) { sendEventObject(e); } public void mouseEntered(MouseEvent e) { sendEventObject(e); } public void mouseExited(MouseEvent e) { sendEventObject(e); } public void mousePressed(MouseEvent e) { sendEventObject(e); } public void mouseReleased(MouseEvent e) { sendEventObject(e); } }); } private static void sendEventObject(InputEvent event){ try{ System.out.println("send"); OOS.writeObject(event); OOS.flush(); }catch(Exception ef){ ef.printStackTrace(); }
以上就完成了控制端。
接下來我們將構(gòu)建被控制端:
被控制端需要使用robot來截圖并發(fā)送,而且需要寫一個(gè)方法來對(duì)接收到的InputEvent進(jìn)行反應(yīng)
首先是截圖和發(fā)送:
public static void CapturePic() throws AWTException, IOException{ robot= new Robot(); Message msg = null; Toolkit tk = java.awt.Toolkit.getDefaultToolkit(); java.awt.Dimension dm =tk.getScreenSize(); java.awt.Robot robot = new java.awt.Robot(); for (int i = 0; i < 50; i++) { //截取指定大小的屏幕區(qū)域 Rectangle rec = new Rectangle(0, 0, (int) dm.getWidth(), (int) dm .getHeight()); BufferedImage bimage = robot.createScreenCapture(rec); //將圖片保存到文件中 String filePath = "D:\\OUT\\screenshot"+i+".jpeg"; FileOutputStream fops =new FileOutputStream(filePath); javax.imageio.ImageIO.write(bimage, "jpeg", fops); fops.flush(); fops.close(); msg =new Message(filePath); System.out.println(msg.getFileName()); System.out.println("send"); OOS.writeObject(msg); OOS.flush(); } }
注意到這段代碼中使用了D:\OUT\目錄作為臨時(shí)文件的存放地方,讀者使用這個(gè)代碼的時(shí)候需要自己設(shè)置臨時(shí)文檔的存放
然后實(shí)現(xiàn)robot對(duì)于接收到的InputEvent指令進(jìn)行操作:
public void action() throws AWTException, ClassNotFoundException, IOException{ Robot robot= new Robot(); while(true){ InputEvent e =(InputEvent)OIS.readObject(); if(e!=null){ handleEvents(robot,e);} } } public static void handleEvents(Robot action,InputEvent event){ MouseEvent mevent = null ; //鼠標(biāo)事件 MouseWheelEvent mwevent = null ;//鼠標(biāo)滾動(dòng)事件 KeyEvent kevent = null ; //鍵盤事件 int mousebuttonmask = -100; //鼠標(biāo)按鍵 switch (event.getID()){ case MouseEvent.MOUSE_MOVED : //鼠標(biāo)移動(dòng) mevent = ( MouseEvent )event ; action.mouseMove( mevent.getX() , mevent.getY() ); break ; case MouseEvent.MOUSE_PRESSED : //鼠標(biāo)鍵按下 mevent = ( MouseEvent ) event; action.mouseMove( mevent.getX() , mevent.getY() ); mousebuttonmask = getMouseClick(mevent.getButton() ); if(mousebuttonmask != -100) action.mousePress(mousebuttonmask); break; case MouseEvent.MOUSE_RELEASED : //鼠標(biāo)鍵松開 mevent = ( MouseEvent ) event; action.mouseMove( mevent.getX() , mevent.getY() ); mousebuttonmask = getMouseClick( mevent.getButton() );//取得鼠標(biāo)按鍵 if(mousebuttonmask != -100) action.mouseRelease( mousebuttonmask ); break ; case MouseEvent.MOUSE_WHEEL : //鼠標(biāo)滾動(dòng) mwevent = ( MouseWheelEvent ) event ; action.mouseWheel(mwevent.getWheelRotation()); break ; case MouseEvent.MOUSE_DRAGGED : //鼠標(biāo)拖拽 mevent = ( MouseEvent ) event ; action.mouseMove( mevent.getX(), mevent.getY() ); break ; case KeyEvent.KEY_PRESSED : //按鍵 kevent = ( KeyEvent ) event; action.keyPress( kevent.getKeyCode() ); break ; case KeyEvent.KEY_RELEASED : //松鍵 kevent= ( KeyEvent ) event ; action.keyRelease( kevent.getKeyCode() ); break ; default: break ; } } private static int getMouseClick(int button) { //取得鼠標(biāo)按鍵 if (button == MouseEvent.BUTTON1) //左鍵 ,中間鍵為BUTTON2 return InputEvent.BUTTON1_MASK; if (button == MouseEvent.BUTTON3) //右鍵 return InputEvent.BUTTON3_MASK; return -100; }
整個(gè)程序到這里就可以結(jié)束了。上面的程序并沒有實(shí)現(xiàn)對(duì)機(jī)器人類線程的封裝。完整可以用的代碼可以在以下站內(nèi)資源處下載我的資源:http://xiazai.jb51.net/201608/yuanma/Java-RomoteControl(jb51.net).rar
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java UrlRewriter偽靜態(tài)技術(shù)運(yùn)用深入分析
- 總結(jié)Java常用到的六個(gè)加密技術(shù)和代碼
- 識(shí)別率很高的java文字識(shí)別技術(shù)
- JAVA Web實(shí)時(shí)消息后臺(tái)服務(wù)器推送技術(shù)---GoEasy
- 分頁技術(shù)原理與實(shí)現(xiàn)之Java+Oracle代碼實(shí)現(xiàn)分頁(二)
- java的poi技術(shù)讀取和導(dǎo)入Excel實(shí)例
- Java中四種XML解析技術(shù)
- PHP、JAVA、.NET這三種技術(shù)的區(qū)別分析
- JAVA使用JDBC技術(shù)操作SqlServer數(shù)據(jù)庫實(shí)例代碼
- 你應(yīng)該知道的21個(gè)Java核心技術(shù)
相關(guān)文章
Spring中的@ControllerAdvice三種用法詳解
這篇文章主要介紹了Spring中的@ControllerAdvice三種用法詳解,加了@ControllerAdvice的類為那些聲明了(@ExceptionHandler、@InitBinder或@ModelAttribute注解修飾的)方法的類而提供的<BR>專業(yè)化的@Component,以供多個(gè)Controller類所共享,需要的朋友可以參考下2024-01-01Java 靜態(tài)數(shù)據(jù)初始化的示例代碼
這篇文章主要介紹了Java 靜態(tài)數(shù)據(jù)初始化的示例代碼,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下2020-09-09java實(shí)現(xiàn)簡單控制臺(tái)五子棋游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡單控制臺(tái)五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11詳解spring Boot 集成 Thymeleaf模板引擎實(shí)例
本篇文章主要介紹了spring Boot 集成 Thymeleaf模板引擎實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09關(guān)于Object中equals方法和hashCode方法判斷的分析
今天小編就為大家分享一篇關(guān)于關(guān)于Object中equals方法和hashCode方法判斷的分析,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-01-01Java基本概念監(jiān)視器實(shí)習(xí)原理解析
這篇文章主要介紹了Java基本概念監(jiān)視器實(shí)習(xí)原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Spring Task定時(shí)任務(wù)每天零點(diǎn)執(zhí)行一次的操作
這篇文章主要介紹了Spring Task定時(shí)任務(wù)每天零點(diǎn)執(zhí)行一次的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09Java實(shí)現(xiàn)LeetCode(54.螺旋矩陣)
這篇文章主要介紹了Java實(shí)現(xiàn)LeetCode(螺旋矩陣),本文列出題目和寫題的思路。給出完整的解法代碼,需要的朋友可以參考下2021-06-06