portaldacalheta.pt
  • Κύριος
  • Κατανεμημένες Ομάδες
  • Τροποσ Ζωησ
  • Αλλα
  • Κερδοφορία & Αποδοτικότητα
Πίσω Μέρος

Εφαρμογή απομακρυσμένου διακομιστή Framebuffer στην Java



Στην πληροφορική, το Virtual Network Computing (VNC) είναι ένα γραφικό σύστημα κοινής χρήσης επιτραπέζιου υπολογιστή που χρησιμοποιεί το πρωτόκολλο Remote Framebuffer (RFB) για τον έλεγχο από απόσταση ενός άλλου υπολογιστή. Μεταδίδει συμβάντα πληκτρολογίου και ποντικιού από τον έναν υπολογιστή στον άλλο και αναμεταδίδει ενημερώσεις οθόνης γραφικών προς την άλλη κατεύθυνση μέσω δικτύου.

Το RFB είναι ένα απλό πρωτόκολλο για απομακρυσμένη πρόσβαση σε γραφικές διεπαφές χρήστη. Επειδή λειτουργεί σε επίπεδο buffer πλαισίου, ισχύει για όλα τα συστήματα και εφαρμογές Window, συμπεριλαμβανομένων των Microsoft Windows, Mac OS X και X Window System.



Δημιουργία μιας εφαρμογής Swing απομακρυσμένου Framebuffer διακομιστή με εφαρμογή πρωτοκόλλου Swing στην Java



Δημιουργία μιας εφαρμογής Swing απομακρυσμένου Framebuffer διακομιστή με εφαρμογή πρωτοκόλλου Swing στην Java Τιτίβισμα

Σε αυτό το άρθρο θα δείξω πώς να εφαρμόσω το πρωτόκολλο διακομιστή RFB και θα δείξω με μια μικρή εφαρμογή Java Swing πώς να μεταδώσετε το κύριο παράθυρο μέσω σύνδεσης TCP σε θεατές VNC. Η ιδέα είναι να δείξουμε βασικά χαρακτηριστικά του πρωτοκόλλου και πιθανή εφαρμογή στην Java.



Ο αναγνώστης πρέπει να έχει βασικές γνώσεις για τη γλώσσα προγραμματισμού Java και θα πρέπει να είναι εξοικειωμένος με τις βασικές έννοιες της δικτύωσης TCP / IP, του μοντέλου διακομιστή-πελάτη κ.λπ. Ιδανικά, ο αναγνώστης είναι Προγραμματιστής Java και έχει κάποια εμπειρία με γνωστές εφαρμογές VNC όπως RealVNC, UltraVNC, TightVNC κ.λπ.

Προδιαγραφή απομακρυσμένου Framebuffer Protocol

Η προδιαγραφή πρωτοκόλλου RFB είναι όμορφη καλά καθορισμένο . Σύμφωνα με την Wikipedia, το πρωτόκολλο RFB έχει διάφορες εκδόσεις. Για αυτό το άρθρο, θα επικεντρωθούμε σε κοινά μηνύματα που πρέπει να κατανοηθούν σωστά από τις περισσότερες εφαρμογές VNC ανεξάρτητα από την έκδοση πρωτοκόλλου.



διαφορά μεταξύ s corporation και llc

Αφού ένα πρόγραμμα προβολής VNC (πελάτης) δημιουργήσει σύνδεση TCP σε διακομιστή VNC (υπηρεσία RFB), η πρώτη φάση περιλαμβάνει την ανταλλαγή της έκδοσης πρωτοκόλλου:

RFB Service ----------- 'RFB 003.003 ' -------> VNC viewer RFB Service <---------- 'RFB 003.008 ' -------- VNC viewer

Είναι μια απλή ροή byte που μπορεί να αποκωδικοποιηθεί Χαρακτήρες ASCII , όπως 'RFB 003.008 n'.



Μόλις γίνει αυτό, το επόμενο βήμα είναι ο έλεγχος ταυτότητας. Ο διακομιστής VNC στέλνει έναν πίνακα byte για να υποδείξει τον τύπο ελέγχου ταυτότητας που υποστηρίζει. Για παράδειγμα:

RFB Service ----------- 0x01 0x02 -----------> VNC viewer RFB Service <----------- 0x02 ----------- VNC viewer

Εδώ ο διακομιστής VNC έστειλε μόνο 1 πιθανό τύπο ελέγχου ταυτότητας (0x02). Το πρώτο byte 0x01 δηλώνει τον αριθμό των διαθέσιμων τύπων ελέγχου ταυτότητας. Το πρόγραμμα προβολής VNC πρέπει να απαντήσει με την τιμή 0x02, καθώς αυτός είναι ο μόνος δυνατός τύπος που υποστηρίζεται από το διακομιστή σε αυτό το παράδειγμα.



Στη συνέχεια, ο διακομιστής θα στείλει πρόκληση ελέγχου ταυτότητας (ανάλογα με τον αλγόριθμο, υπάρχουν αρκετοί) και ο πελάτης πρέπει να απαντήσει με το κατάλληλο μήνυμα απόκρισης πρόκλησης και να περιμένει τον διακομιστή να επιβεβαιώσει την απόκριση. Μόλις γίνει έλεγχος ταυτότητας του πελάτη, μπορεί να συνεχίσει τη διαδικασία δημιουργίας συνεδρίας.

Ο απλούστερος τρόπος εδώ είναι να μην επιλέξετε καθόλου έλεγχο ταυτότητας. Το πρωτόκολλο RFB είναι πάντως ανασφαλές, ανεξάρτητα από τον μηχανισμό ελέγχου ταυτότητας. Εάν η ασφάλεια είναι σημαντική, ο σωστός τρόπος θα ήταν να διοχετεύσετε συνεδρίες RFB μέσω συνδέσεων VPN ή SSH.



Σε αυτό το σημείο, το πρόγραμμα προβολής VNC στέλνει ένα κοινόχρηστο μήνυμα επιτραπέζιου υπολογιστή που λέει εάν ο πελάτης θα μοιραστεί και θα επιτρέψει σε άλλους θεατές VNC να συνδεθούν στον ίδιο υπολογιστή. Εναπόκειται στην εφαρμογή της υπηρεσίας RFB να εξετάσει αυτό το μήνυμα και ενδεχομένως να εμποδίσει πολλούς θεατές VNC να μοιραστούν την ίδια οθόνη. Αυτό το μήνυμα έχει μήκος μόνο 1 byte και μια έγκυρη τιμή είναι 0x00 ή 0x01.

Τέλος, ο διακομιστής RFB στέλνει ένα μήνυμα init διακομιστή, ο οποίος περιέχει διάσταση οθόνης, bits ανά pixel, βάθος, μεγάλη σημαία endian και πραγματικές χρωματικές σημαίες, μέγιστες τιμές για κόκκινα, πράσινα και μπλε χρώματα, θέσεις bit σε pixel για κόκκινα, πράσινα και μπλε χρώματα , και συμβολοσειρά / τίτλος επιφάνειας εργασίας. Τα πρώτα δύο byte αντιπροσωπεύουν το πλάτος της οθόνης σε pixel, ενώ τα επόμενα δύο byte είναι το ύψος της οθόνης. Μετά το byte ύψους οθόνης, θα πρέπει να υπάρχουν bits ανά pixel byte στο μήνυμα. Η τιμή είναι συνήθως 8, 16 ή 32. Στα περισσότερα σύγχρονα συστήματα με πλήρες εύρος χρωμάτων, τα bit ανά pixel byte έχουν τιμή 32 (0x20). Λέει στον πελάτη ότι μπορεί να ζητήσει πλήρες χρώμα για κάθε pixel από το διακομιστή. Το μεγάλο endian byte δεν είναι μηδενικό μόνο εάν τα pixel είναι σε μεγάλη σειρά endian. Εάν το πραγματικό byte χρώματος δεν είναι μηδέν (true), τότε τα επόμενα έξι byte καθορίζουν τον τρόπο εξαγωγής των εντάσεων χρώματος κόκκινου, πράσινου και μπλε από την τιμή των pixel. Τα επόμενα έξι byte είναι οι μέγιστες επιτρεπόμενες τιμές για κόκκινο, πράσινο και μπλε στοιχείο pixel. Αυτό είναι σημαντικό σε λειτουργία χρώματος 8-bit, όπου μόνο λίγα bits είναι διαθέσιμα για κάθε χρωματικό στοιχείο. Οι μετατοπίσεις κόκκινου, πράσινου και μπλε καθορίζουν τις θέσεις bit για κάθε χρώμα. Τα τελευταία τρία byte γεμίζουν και πρέπει να αγνοηθούν από τον πελάτη. Μετά τη μορφή pixel, υπάρχει ένα byte που καθορίζει το μήκος μιας συμβολοσειράς για τον τίτλο της επιφάνειας εργασίας. Ο τίτλος της επιφάνειας εργασίας είναι μια κωδικοποιημένη ASCII συμβολοσειρά σε πίνακα byte αυθαίρετου μήκους.



Πρωτόκολλο διακομιστή-πελάτη απομακρυσμένου Framebuffer: ανταλλαγή εκδόσεων, έλεγχος ταυτότητας και init μήνυμα διακομιστή

Πρωτόκολλο διακομιστή-πελάτη απομακρυσμένου Framebuffer: ανταλλαγή εκδόσεων, έλεγχος ταυτότητας και init μήνυμα διακομιστή Τιτίβισμα

Μετά το μήνυμα init διακομιστή, η υπηρεσία RFB θα πρέπει να διαβάζει μηνύματα πελάτη από την υποδοχή και να τα αποκωδικοποιεί. Υπάρχουν 6 τύποι μηνυμάτων:

  • SetPixelFormat
  • SetEncodings
  • FramebufferUpdateRequest
  • KeyEvent
  • PointerEvent
  • ClientCutText

Η τεκμηρίωση πρωτοκόλλου είναι αρκετά ακριβής και εξηγεί κάθε μήνυμα. Για κάθε μήνυμα, εξηγείται κάθε byte. Για παράδειγμα, το μήνυμα init διακομιστή:

Αριθμός byte Τύπος Περιγραφή
2 U16 πλάτος framebuffer
2 U16 framebuffer-ύψος
16 PIXEL_FORMAT μορφή διακομιστή-pixel
4 U32 μήκος ονόματος
μήκος ονόματος Πίνακας U8 συμβολοσειρά ονόματος

Εδώ, το PIXEL_FORMAT είναι:

Αριθμός byte Τύπος Περιγραφή
ένας U8 bit ανά εικονοστοιχείο
ένας U8 βάθος
ένας U8 μεγάλη-τελική σημαία
ένας U8 true-color-flag
2 U16 κόκκινο-μέγ
2 U16 πράσινο-μέγ
2 U16 μπλε-μέγ
ένας U8 κόκκινη μετατόπιση
ένας U8 πράσινη μετατόπιση
ένας U8 μπλε-μετατόπιση
3 υλικό παραγεμίσματος

Το U16 σημαίνει ακέραιο 16-bit χωρίς υπογραφή (δύο byte), το U32 είναι ακέραιο 32-bit χωρίς υπογραφή, ο πίνακας U8 είναι πίνακας byte κ.λπ.

Εφαρμογή πρωτοκόλλου στην Java

Μια τυπική εφαρμογή διακομιστή Java αποτελείται από ένα νήμα που ακούει για συνδέσεις πελατών και πολλά νήματα που χειρίζονται συνδέσεις πελατών.

/* * Use TCP port 5902 (display :2) as an example to listen. */ int port = 5902; ServerSocket serverSocket; serverSocket = new ServerSocket(port); /* * Limit sessions to 100. This is lazy way, if * somebody really open 100 sessions, server socket * will stop listening and no new VNC viewers will be * able to connect. */ while (rfbClientList.size() <100) { /* * Wait and accept new client. */ Socket client = serverSocket.accept(); /* * Create new object for each client. */ RFBService rfbService = new RFBService(client); /* * Add it to list. */ rfbClientList.add(rfbService); /* * Handle new client session in separate thread. */ (new Thread(rfbService, 'RFBService' + rfbClientList.size())).start(); }

Εδώ επιλέχθηκε η θύρα TCP 5902 (οθόνη: 2) και ο loop loop περιμένει να συνδεθεί ένας πελάτης. Μέθοδος ServerSocket.accept () αποκλείει και κάνει το νήμα να περιμένει μια νέα σύνδεση πελάτη. Μόλις συνδεθεί ο πελάτης, δημιουργείται ένα νέο νήμα RFBService που χειρίζεται τα μηνύματα πρωτοκόλλου RFB που λαμβάνονται από τον πελάτη.

Το Class RFBService εφαρμόζει διεπαφή με δυνατότητα εκτέλεσης. Είναι γεμάτο μεθόδους ανάγνωσης bytes από την υποδοχή. Μέθοδος τρέξιμο() είναι σημαντικό, το οποίο εκτελείται αμέσως όταν το νήμα ξεκινά στο τέλος του βρόχου:

@Override public void run() { try { /* * RFB server has to send protocol version string first. * And wait for VNC viewer to replay with * protocol version string. */ sendProtocolVersion(); String protocolVer = readProtocolVersion(); if (!protocolVer.startsWith('RFB')) { throw new IOException(); }

Εδώ μέθοδο αποστολήProtocolVersion () στέλνει συμβολοσειρά RFB στον πελάτη (πρόγραμμα προβολής VNC) και μετά διαβάζει τη συμβολοσειρά έκδοσης πρωτοκόλλου από τον πελάτη. Ο πελάτης πρέπει να απαντήσει με κάτι σαν 'RFB 003.008 n'. Μέθοδος ΔιαβάστεProtocolVersion () είναι φυσικά αποκλεισμός, όπως οποιαδήποτε μέθοδος του οποίου το όνομα ξεκινά με τη λέξη ανάγνωσης.

private String readProtocolVersion() throws IOException { byte[] buffer = readU8Array(12); return new String(buffer); }

Η μέθοδος readProtocolVersion () είναι απλή: διαβάζει 12 byte από την υποδοχή και επιστρέφει μια τιμή συμβολοσειράς. Η συνάρτηση readU8Array (int) διαβάζει καθορισμένο αριθμό byte, στην περίπτωση αυτή 12 bytes. Εάν δεν υπάρχουν αρκετά bytes για ανάγνωση στην υποδοχή, περιμένει:

private byte[] readU8Array(int len) throws IOException { byte[] buffer = new byte[len]; int offset = 0, left = buffer.length; while (offset

Παρόμοιο με readU8Array (int) , μέθοδοι readU16int () και readU32int () υπάρχουν που διαβάζουν byte από την υποδοχή και επιστρέφουν ακέραια τιμή.

απλό πρότυπο εγγράφου τεχνικής σχεδίασης

Μετά την αποστολή της έκδοσης πρωτοκόλλου και την ανάγνωση της απάντησης, η υπηρεσία RFB θα πρέπει να στείλει μήνυμα ασφαλείας:

/* * RFB server sends security type bytes that may request * a user to type password. * In this implementation, this is set to simples * possible option: no authentication at all. */ sendSecurityType();

Σε αυτήν την εφαρμογή, επιλέγεται ο απλούστερος τρόπος: δεν απαιτείται κωδικός πρόσβασης από την πλευρά του πελάτη VNC.

private void sendSecurityType() throws IOException { out.write(SECURITY_TYPE); out.flush(); }

όπου SECURITY_TYPE είναι πίνακας byte:

private final byte[] SECURITY_TYPE = {0x00, 0x00, 0x00, 0x01};

Αυτή η σειρά bytes με πρωτόκολλο RFB έκδοση 3.3 σημαίνει ότι το πρόγραμμα προβολής VNC δεν χρειάζεται να στείλει κωδικό πρόσβασης.

Στη συνέχεια, τι πρέπει να λάβει η υπηρεσία RFB από τον πελάτη είναι η κοινόχρηστη σημαία επιφάνειας εργασίας. Είναι ένα byte στην πρίζα.

/* * RFB server reads shared desktop flag. It's a single * byte that tells RFB server * should it support multiple VNC viewers connected at * same time or not. */ byte sharedDesktop = readSharedDesktop();

Μόλις διαβαστεί η κοινόχρηστη σημαία της επιφάνειας εργασίας από την υποδοχή, την αγνοούμε κατά την εφαρμογή μας.

Η υπηρεσία RFB πρέπει να στείλει μήνυμα στο διακομιστή:

/* * RFB server sends ServerInit message that includes * screen resolution, * number of colors, depth, screen title, etc. */ screenWidth = JFrameMainWindow.jFrameMainWindow.getWidth(); screenHeight = JFrameMainWindow.jFrameMainWindow.getHeight(); String windowTitle = JFrameMainWindow.jFrameMainWindow.getTitle(); sendServerInit(screenWidth, screenHeight, windowTitle);

Η κλάση JFrameMainWindow είναι JFrame, η οποία είναι εδώ για επίδειξη ως πηγή γραφικών. Το μήνυμα init διακομιστή έχει υποχρεωτικό πλάτος και ύψος οθόνης σε pixel και τίτλο επιφάνειας εργασίας. Σε αυτό το παράδειγμα είναι ο τίτλος του JFrame που αποκτήθηκε με τη μέθοδο getTitle ().

Μετά το μήνυμα init διακομιστή, το νήμα υπηρεσίας RFB βγαίνει διαβάζοντας από την υποδοχή έξι τύπους μηνυμάτων:

/* * Main loop where clients messages are read from socket. */ while (true) { /* * Mark first byte and read it. */ in.mark(1); int messageType = in.read(); if (messageType == -1) { break; } /* * Go one byte back. */ in.reset(); /* * Depending on message type, read complete message on socket. */ if (messageType == 0) { /* * Set Pixel Format */ readSetPixelFormat(); } else if (messageType == 2) { /* * Set Encodings */ readSetEncoding(); } else if (messageType == 3) { /* * Frame Buffer Update Request */ readFrameBufferUpdateRequest(); } else if (messageType == 4) { /* * Key Event */ readKeyEvent(); } else if (messageType == 5) { /* * Pointer Event */ readPointerEvent(); } else if (messageType == 6) { /* * Client Cut Text */ readClientCutText(); } else { err('Unknown message type. Received message type = ' + messageType); } }

Κάθε μέθοδος readSetPixelFormat () , readSetEncoding () , readFrameBufferUpdateRequest () , ... readClientCutText () αποκλείει και ενεργοποιεί κάποια ενέργεια.

Για παράδειγμα, readClientCutText () Η μέθοδος διαβάζει κείμενο που κωδικοποιείται στο μήνυμα όταν ο χρήστης κόβει κείμενο από την πλευρά του πελάτη και στη συνέχεια ο θεατής VNC στέλνει κείμενο μέσω πρωτοκόλλου RFB στον διακομιστή. Στη συνέχεια, το κείμενο τοποθετείται στην πλευρά του διακομιστή στο Πρόχειρο.

Μηνύματα πελατών

Και τα έξι μηνύματα πρέπει να υποστηρίζονται από την υπηρεσία RFB, τουλάχιστον σε επίπεδο byte: όταν ο πελάτης στέλνει μήνυμα, πρέπει να διαβαστεί ένα πλήρες μήκος byte. Αυτό συμβαίνει επειδή το πρωτόκολλο RFB είναι προσανατολισμένο σε byte και δεν υπάρχει όριο μεταξύ δύο μηνυμάτων.

Το πιο σημαντικό μήνυμα εισαγωγής είναι το αίτημα ενημέρωσης καρέ buffer. Ο πελάτης μπορεί να ζητήσει πλήρη ενημέρωση ή σταδιακή ενημέρωση της οθόνης.

private void readFrameBufferUpdateRequest() throws IOException { int messageType = in.read(); int incremental = in.read(); if (messageType == 0x03) { int x_pos = readU16int(); int y_pos = readU16int(); int width = readU16int(); int height = readU16int(); screenWidth = width; screenHeight = height; if (incremental == 0x00) { incrementalFrameBufferUpdate = false; int x = JFrameMainWindow.jFrameMainWindow.getX(); int y = JFrameMainWindow.jFrameMainWindow.getY(); RobotScreen.robo.getScreenshot(x, y, width, height); sendFrameBufferUpdate(x_pos, y_pos, width, height, 0, RobotScreen.robo.getColorImageBuffer()); } else if (incremental == 0x01) { incrementalFrameBufferUpdate = true; } else { throw new IOException(); } } else { throw new IOException(); } }

Το πρώτο byte του μηνύματος αιτήματος buffer καρέ είναι ο τύπος μηνύματος. Η τιμή είναι πάντα 0x03. Το επόμενο byte είναι η σταδιακή σημαία, η οποία λέει στον διακομιστή να στείλει πλήρες καρέ ή απλά μια διαφορά. Σε περίπτωση πλήρους αιτήματος ενημέρωσης, η υπηρεσία RFB θα τραβήξει στιγμιότυπο οθόνης του κύριου παραθύρου χρησιμοποιώντας την κλάση RobotScreen και θα την στείλει στον πελάτη.

Εάν πρόκειται για αυξητικό αίτημα, επισημάνετε incrementalFrameBufferUpdate θα οριστεί ως αληθής. Αυτή η σημαία θα χρησιμοποιηθεί από τα στοιχεία Swing για να ελέγξει εάν πρέπει να στείλουν μέρη της οθόνης που έχουν αλλάξει. Συνήθως τα JMenu, JMenuItem, JTextArea, κ.λπ. πρέπει να κάνουν σταδιακή ενημέρωση της οθόνης όταν ο χρήστης μετακινεί το δείκτη του ποντικιού, κάνει κλικ, στέλνει πλήκτρα κλπ.

Η μέθοδος sendFrameBufferUpdate (int, int, int, int, int []) ξεπλένει το buffer εικόνας στην υποδοχή.

public void sendFrameBufferUpdate(int x, int y, int width, int height, int encodingType, int[] screen) throws IOException { if (x + width > screenWidth || y + height > screenHeight) { err ('Invalid frame update size:'); err (' x = ' + x + ', y = ' + y); err (' width = ' + width + ', height = ' + height); return; } byte messageType = 0x00; byte padding = 0x00; out.write(messageType); out.write(padding); int numberOfRectangles = 1; writeU16int(numberOfRectangles); writeU16int(x); writeU16int(y); writeU16int(width); writeU16int(height); writeS32int(encodingType); for (int rgbValue : screen) { int red = (rgbValue & 0x000000FF); int green = (rgbValue & 0x0000FF00) >> 8; int blue = (rgbValue & 0x00FF0000) >> 16; if (bits_per_pixel == 8) { out.write((byte) colorMap.get8bitPixelValue(red, green, blue)); } else { out.write(red); out.write(green); out.write(blue); out.write(0); } } out.flush(); }

Η μέθοδος ελέγχει ότι η συντεταγμένη (x, y) δεν βγαίνει από την οθόνη μαζί με το πλάτος x ύψος της προσωρινής μνήμης εικόνας. Η τιμή του τύπου μηνύματος για την ενημέρωση του buffer πλαισίου είναι 0x00. Η τιμή γεμίσματος είναι συνήθως 0x00 και πρέπει να αγνοηθεί από το πρόγραμμα προβολής VNC. Ο αριθμός των ορθογωνίων είναι τιμή δύο byte και καθορίζει πόσα ορθογώνια ακολουθούν στο μήνυμα.

Κάθε ορθογώνιο έχει πάνω αριστερή συντεταγμένη, πλάτος και ύψος, τύπο κωδικοποίησης και δεδομένα pixel. Υπάρχουν μερικές αποτελεσματικές μορφές κωδικοποίησης που μπορούν να χρησιμοποιηθούν, όπως το zrle, το hextile και το σφιχτό. Ωστόσο, για να διατηρήσουμε τα πράγματα απλά και εύκολα κατανοητά, θα χρησιμοποιήσουμε ακατέργαστη κωδικοποίηση στην εφαρμογή μας.

Η ακατέργαστη κωδικοποίηση σημαίνει ότι το χρώμα των pixel μεταδίδεται ως συστατικό RGB. Εάν ο πελάτης έχει ορίσει κωδικοποίηση pixel ως 32-bit, τότε μεταδίδονται 4 byte για κάθε pixel. Εάν ο πελάτης χρησιμοποιεί λειτουργία χρώματος 8-bit, τότε κάθε pixel μεταδίδεται ως 1 byte. Ο κωδικός εμφανίζεται στο for-loop. Σημειώστε ότι για τη λειτουργία 8 bit χρησιμοποιείται έγχρωμος χάρτης για την εύρεση της καλύτερης αντιστοίχισης για κάθε εικονοστοιχείο από το στιγμιότυπο οθόνης / την προσωρινή μνήμη εικόνας. Για τη λειτουργία 32-bit pixel, το buffer εικόνας περιέχει μια σειρά από ακέραιους αριθμούς, κάθε τιμή έχει πολλαπλά στοιχεία RGB.

Εφαρμογή επίδειξης Swing

Η εφαρμογή επίδειξης Swing περιέχει ακροατή δράσης που ενεργοποιεί sendFrameBufferUpdate (int, int, int, int, int []) μέθοδος. Συνήθως τα στοιχεία εφαρμογής, όπως τα στοιχεία Swing, πρέπει να έχουν ακροατές και να στέλνουν αλλαγή οθόνης στον πελάτη. Όπως όταν ο χρήστης πληκτρολογεί κάτι στο JTextArea, θα πρέπει να μεταδοθεί στο πρόγραμμα προβολής VNC.

public void actionPerformed(ActionEvent arg0) { /* * Get dimensions and location of main JFrame window. */ int offsetX = JFrameMainWindow.jFrameMainWindow.getX(); int offsetY = JFrameMainWindow.jFrameMainWindow.getY(); int width = JFrameMainWindow.jFrameMainWindow.getWidth(); int height = JFrameMainWindow.jFrameMainWindow.getHeight(); /* * Do not update screen if main window dimension has changed. * Upon main window resize, another action listener will * take action. */ int screenWidth = RFBDemo.rfbClientList.get(0).screenWidth; int screenHeight = RFBDemo.rfbClientList.get(0).screenHeight; if (width != screenWidth || height != screenHeight) { return; } /* * Capture new screenshot into image buffer. */ RobotScreen.robo.getScreenshot(offsetX, offsetY, width, height); int[] delta = RobotScreen.robo.getDeltaImageBuffer(); if (delta == null) { offsetX = 0; offsetY = 0; Iterator it = RFBDemo.rfbClientList.iterator(); while (it.hasNext()) { RFBService rfbClient = it.next(); if (rfbClient.incrementalFrameBufferUpdate) { try { /* * Send complete window. */ rfbClient.sendFrameBufferUpdate( offsetX, offsetY, width, height, 0, RobotScreen.robo.getColorImageBuffer()); } catch (SocketException ex) { it.remove(); } catch (IOException ex) { ex.printStackTrace(); it.remove(); } rfbClient.incrementalFrameBufferUpdate = false; } } } else { offsetX = RobotScreen.robo.getDeltaX(); offsetY = RobotScreen.robo.getDeltaY(); width = RobotScreen.robo.getDeltaWidth(); height = RobotScreen.robo.getDeltaHeight(); Iterator it = RFBDemo.rfbClientList.iterator(); while (it.hasNext()) { RFBService rfbClient = it.next(); if (rfbClient.incrementalFrameBufferUpdate) { try { /* * Send only delta rectangle. */ rfbClient.sendFrameBufferUpdate( offsetX, offsetY, width, height, 0, delta); } catch (SocketException ex) { it.remove(); } catch (IOException ex) { ex.printStackTrace(); it.remove(); } rfbClient.incrementalFrameBufferUpdate = false; } } } }

Ο κώδικας αυτού του ακροατή δράσης είναι πολύ απλός: παίρνει ένα στιγμιότυπο οθόνης του κύριου παραθύρου JFrameMain χρησιμοποιώντας την κλάση RobotScreen και, στη συνέχεια, καθορίζεται εάν απαιτείται μερική ενημέρωση της οθόνης. Μεταβλητός diffUpdateOfScreen χρησιμοποιείται ως σημαία για μερική ενημέρωση. Και τέλος, πλήρης προσωρινή μνήμη εικόνας ή μόνο διαφορετικές σειρές μεταδίδονται στον πελάτη. Αυτός ο κώδικας εξετάζει επίσης περισσότερους πελάτες συνδεδεμένους, γι 'αυτό χρησιμοποιείται ο επαναληπτής και διατηρείται η λίστα πελατών RFBDemo.rfbClientList μέλος.

Το πρόγραμμα ακρόασης δράσης ενημέρωσης Framebuffer θα μπορούσε να χρησιμοποιηθεί στο Χρονοδιακόπτη, το οποίο μπορεί να ξεκινήσει με οποιαδήποτε αλλαγή JComponent:

/* * Define timer for frame buffer update with 400 ms delay and * no repeat. */ timerUpdateFrameBuffer = new Timer(400, new ActionListenerFrameBufferUpdate()); timerUpdateFrameBuffer.setRepeats(false);

Αυτός ο κωδικός είναι στον κατασκευαστή της κλάσης JFrameMainWindow. Το χρονόμετρο ξεκινά με τη μέθοδο doIncrementalFrameBufferUpdate ():

πώς να χρησιμοποιήσετε το discord api
public void doIncrementalFrameBufferUpdate() { if (RFBDemo.rfbClientList.size() == 0) { return; } if (!timerUpdateFrameBuffer.isRunning()) { timerUpdateFrameBuffer.start(); } }

Οι άλλοι ακροατές δράσης καλούν συνήθως τη μέθοδο doIncrementalFrameBufferUpdate ():

public class DocumentListenerChange implements DocumentListener { @Override public void changedUpdate(DocumentEvent e) { JFrameMainWindow jFrameMainWindow = JFrameMainWindow.jFrameMainWindow; jFrameMainWindow.doIncrementalFrameBufferUpdate(); } // ... }

Αυτός ο τρόπος πρέπει να είναι απλός και εύκολο να ακολουθηθεί. Απαιτείται μόνο μια αναφορά στην παρουσία JFrameMainWindow και με μία κλήση doIncrementalFrameBufferUpdate () μέθοδος. Η μέθοδος θα ελέγξει εάν υπάρχουν συνδεδεμένοι πελάτες και, εάν υπάρχουν, χρονόμετρο timerUpdateFrameBuffer θα ξεκινήσει. Μόλις ξεκινήσει ο χρονοδιακόπτης, ο ακροατής δράσης θα λάβει πραγματικά στιγμιότυπο οθόνης και sendFrameBufferUpdate () εκτελείται.

Η παραπάνω εικόνα δείχνει τη σχέση του ακροατή με τη διαδικασία ενημέρωσης καρέ buffer. Οι περισσότεροι ακροατές ενεργοποιούνται όταν ο χρήστης κάνει ενέργεια: κάνει κλικ, επιλέγει κείμενο, πληκτρολογεί κάτι στην περιοχή κειμένου κ.λπ. Στη συνέχεια, η λειτουργία μέλους doIncrementalFramebufferUpdate () εκτελείται που ξεκινά το χρονόμετρο timerUpdateFrameBuffer . Ο χρονοδιακόπτης θα καλέσει τελικά sendFrameBufferUpdate () μέθοδος στην κλάση RFBService και θα προκαλέσει ενημέρωση οθόνης από την πλευρά του πελάτη (VNC viewer).

Λήψη οθόνης, αναπαραγωγή πλήκτρων και μετακίνηση δείκτη ποντικιού στην οθόνη

Η Java διαθέτει μια ενσωματωμένη κλάση ρομπότ που επιτρέπει στον προγραμματιστή να γράψει μια εφαρμογή που θα τραβήξει στιγμιότυπα οθόνης, θα στείλει κλειδιά, θα χειριστεί το δείκτη του ποντικιού, θα παράγει κλικ κ.λπ.

Για να αρπάξετε την περιοχή της οθόνης όπου εμφανίζεται το παράθυρο JFrame, χρησιμοποιείται το RobotScreen. Η κύρια μέθοδος είναι getScreenshot (int, int, int, int) που καταγράφει μια περιοχή οθόνης. Οι τιμές RGB για κάθε pixel αποθηκεύονται σε έναν πίνακα int []:

public void getScreenshot(int x, int y, int width, int height) { Rectangle screenRect = new Rectangle(x, y, width, height); BufferedImage colorImage = robot.createScreenCapture(screenRect); previousImageBuffer = colorImageBuffer; colorImageBuffer = ((DataBufferInt) colorImage.getRaster().getDataBuffer()).getData(); if (previousImageBuffer == null || previousImageBuffer.length != colorImageBuffer.length) { previousImageBuffer = colorImageBuffer; } this.width = width; this.height = height; }

Η μέθοδος αποθηκεύει εικονοστοιχεία σε πίνακα colorImageBuffer. Για να λάβετε δεδομένα pixel, getColorImageBuffer () μέθοδος μπορεί να χρησιμοποιηθεί.

Η μέθοδος αποθηκεύει επίσης το προηγούμενο buffer εικόνας. Είναι δυνατή η λήψη μόνο εικονοστοιχείων που έχουν αλλάξει. Για να λάβετε μόνο διαφορά περιοχής εικόνας, χρησιμοποιήστε τη μέθοδο getDeltaImageBuffer () .

Η αποστολή πλήκτρων στο σύστημα είναι εύκολη με την κατηγορία Robot. Ωστόσο, ορισμένοι ειδικοί κωδικοί κλειδιών που λαμβάνονται από τους θεατές VNC πρέπει πρώτα να μεταφραστούν σωστά. Η κλάση RobotKeyboard έχει μέθοδο sendKey (int, int) που χειρίζεται ειδικά πλήκτρα και αλφαριθμητικά πλήκτρα:

public void sendKey(int keyCode, int state) { switch (keyCode) { case 0xff08: doType(VK_BACK_SPACE, state); break; case 0xff09: doType(VK_TAB, state); break; case 0xff0d: case 0xff8d: doType(VK_ENTER, state); break; case 0xff1b: doType(VK_ESCAPE, state); break; … case 0xffe1: case 0xffe2: doType(VK_SHIFT, state); break; case 0xffe3: case 0xffe4: doType(VK_CONTROL, state); break; case 0xffe9: case 0xffea: doType(VK_ALT, state); break; default: /* * Translation of a..z keys. */ if (keyCode >= 97 && keyCode <= 122) { /* * Turn lower-case a..z key codes into upper-case A..Z key codes. */ keyCode = keyCode - 32; } doType(keyCode, state); } }

Η κατάσταση του επιχειρήματος καθορίζει εάν το πλήκτρο πατηθεί ή απελευθερωθεί. Μετά τη σωστή μετάφραση του κλειδιού κώδικα σε VT σταθερά, μέθοδος doType (int, int) τιμή κλειδιού μεταβίβασης στο ρομπότ και το αποτέλεσμα είναι ίδιο με τον τοπικό χρήστη που έχει πατήσει το πλήκτρο στο πληκτρολόγιο:

private void doType(int keyCode, int state) { if (state == 0) { robot.keyRelease(keyCode); } else { robot.keyPress(keyCode); } }

Παρόμοια με το RobotKeyboard είναι η κλάση RobotMouse που χειρίζεται συμβάντα δείκτη και προκαλεί την κίνηση και το κλικ του δείκτη του ποντικιού.

public void mouseMove(int x, int y) { robot.mouseMove(x, y); }

Και οι τρεις τάξεις RobotScreen, RobotMouse και RobotKeyboard διαθέτουν νέα παρουσία ρομπότ στον κατασκευαστή:

this.robot = new Robot();

Έχουμε μόνο μία παρουσία καθεμιάς, αφού δεν χρειάζεται να υπάρχουν περισσότερες από μία εμφανίσεις κλάσης RobotScreen, RobotMouse ή RobotKeyboard.

public static void main(String[] args) { ... /* * Initialize static Robot objects for screen, keyboard and mouse. */ RobotScreen.robo = new RobotScreen(); RobotKeyboard.robo = new RobotKeyboard(); RobotMouse.robo = new RobotMouse(); ... }

Σε αυτήν την εφαρμογή επίδειξης δημιουργούνται αυτές οι παρουσίες κύριος() λειτουργία.

Το αποτέλεσμα είναι μια εφαρμογή που βασίζεται σε Swing στην Java, η οποία λειτουργεί ως πάροχος υπηρεσιών RFB και επιτρέπει στους τυπικούς θεατές VNC να συνδεθούν σε αυτό:

συμπέρασμα

Το πρωτόκολλο RFB χρησιμοποιείται ευρέως και γίνεται αποδεκτό. Υλοποιήσεις πελατών σε μορφή προβολέων VNC υπάρχουν για όλες σχεδόν τις πλατφόρμες και συσκευές. Ο κύριος σκοπός είναι να εμφανίζονται απομακρυσμένοι επιτραπέζιοι υπολογιστές, αλλά μπορεί να υπάρχουν και άλλες εφαρμογές. Για παράδειγμα, θα μπορούσατε να δημιουργήσετε όμορφα εργαλεία γραφικών και να αποκτήσετε πρόσβαση σε αυτά από απόσταση για να βελτιώσετε το υπάρχον απομακρυσμένες ροές εργασίας .

Αυτό το άρθρο καλύπτει τα βασικά του πρωτοκόλλου RFB, τη μορφή μηνύματος, τον τρόπο αποστολής μέρους της οθόνης και τον τρόπο αντιμετώπισης του πληκτρολογίου και του ποντικιού. Ο πλήρης πηγαίος κώδικας με την εφαρμογή επίδειξης Swing είναι διαθέσιμο στο GitHub .

Χρήση του Scala.js με NPM και Browserify

Πίσω Μέρος

Χρήση του Scala.js με NPM και Browserify
Μείνετε Sharp - Πώς να ενισχύσετε τη δημιουργικότητα όταν υποχωρεί η εργασία

Μείνετε Sharp - Πώς να ενισχύσετε τη δημιουργικότητα όταν υποχωρεί η εργασία

Εργαλεία Και Σεμινάρια

Δημοφιλείς Αναρτήσεις
Πώς να δημιουργήσετε μια εφαρμογή επεξεργασίας φυσικής γλώσσας
Πώς να δημιουργήσετε μια εφαρμογή επεξεργασίας φυσικής γλώσσας
Πρόβλεψη επενδυτικού κεφαλαίου 2017: Σημάδια κόπωσης
Πρόβλεψη επενδυτικού κεφαλαίου 2017: Σημάδια κόπωσης
Μια βαθιά ματιά στο JSON εναντίον XML, Μέρος 2: Τα δυνατά σημεία και οι αδυναμίες και των δύο
Μια βαθιά ματιά στο JSON εναντίον XML, Μέρος 2: Τα δυνατά σημεία και οι αδυναμίες και των δύο
Πώς να ποσοτικοποιήσετε αποτελεσματικά την αξία προϊόντος - Ένας οδηγός για τους διαχειριστές προϊόντων
Πώς να ποσοτικοποιήσετε αποτελεσματικά την αξία προϊόντος - Ένας οδηγός για τους διαχειριστές προϊόντων
Το μέλλον των ομάδων: Διαχείριση του συνδυασμένου εργατικού δυναμικού
Το μέλλον των ομάδων: Διαχείριση του συνδυασμένου εργατικού δυναμικού
 
Think Business - Πώς να αυξήσετε την αξία του σχεδιαστή σας
Think Business - Πώς να αυξήσετε την αξία του σχεδιαστή σας
Εργονομία για Ψηφιακούς Νομάδες: Εργασία στο δρόμο χωρίς να σκοτωθείτε
Εργονομία για Ψηφιακούς Νομάδες: Εργασία στο δρόμο χωρίς να σκοτωθείτε
Μια βαθιά κατάδυση στις επενδύσεις του Elon Musk: The Makings of a Billionaire
Μια βαθιά κατάδυση στις επενδύσεις του Elon Musk: The Makings of a Billionaire
Αρχιτεκτονικοί Αλγόριθμοι Βελτιστοποίησης με HorusLP
Αρχιτεκτονικοί Αλγόριθμοι Βελτιστοποίησης με HorusLP
Κοιτάζοντας τα αποτυχημένα IPO στην εποχή του μονόκερου
Κοιτάζοντας τα αποτυχημένα IPO στην εποχή του μονόκερου
Δημοφιλείς Αναρτήσεις
  • τιμές ολόκληρων τροφίμων έναντι walmart
  • εάν η ελαστικότητα της ζήτησης μετρηθεί 2, αυτό σημαίνει ότι οι καταναλωτές θα το έκαναν
  • Διαρροές μνήμης σε παράδειγμα java
  • το κόστος της πρόσληψης ενός υπαλλήλου αριθμομηχανή
  • τα ερωτήματα πολυμέσων για έναν ιστότοπο που χρησιμοποιεί αποκριτικό σχεδιασμό
  • αυτό δεν είναι ιστότοπος γνωριμιών για διαφημίσεις κορίτσι
  • είναι η llc an s ή c corp μου
Κατηγορίες
  • Κατανεμημένες Ομάδες
  • Τροποσ Ζωησ
  • Αλλα
  • Κερδοφορία & Αποδοτικότητα
  • © 2022 | Ολα Τα Δικαιώματα Διατηρούνται

    portaldacalheta.pt