{"id":9,"date":"2007-11-30T18:05:00","date_gmt":"2007-12-01T02:05:00","guid":{"rendered":"http:\/\/www.zackgrossbart.com\/hackito\/2007\/11\/30\/create-a-shared-peer-to-peer-clipboard\/"},"modified":"2009-12-09T15:07:25","modified_gmt":"2009-12-09T23:07:25","slug":"shared-clipboard","status":"publish","type":"post","link":"http:\/\/www.zackgrossbart.com\/hackito\/shared-clipboard\/","title":{"rendered":"Create a Shared Peer-to-Peer Clipboard"},"content":{"rendered":"<p>\nI often work with two computers simultaneously.  Each of those computers runs a different operating system.  That work often includes the need send long strings (like long  URLs) from one computer to the other.  It isn&#8217;t easy.  I have seen all kinds of solutions to this problem including emailing the strings back and forth or checking them into a version control system. I have even seen people maintain a web server just to post strings to copy.\n<\/p>\n<p>\nThis application presents a very simple user interface which enables you to copy a string from one machine and paste it to the other.  It is called NetPaste.  NetPaste is a peer-to-peer application.  Most networked applications are client-server applications, which separate the computers in the network into clients and servers.  The clients talk directly to the servers and make requests.  The servers simply respond to requests from the client.  The clients never talk to each other.  This is the way web browsing works.\n<\/p>\n<p>\nPeer-to-peer (or P2P) lets each computer be both a client and a server.  The computers contact each other and make requests going in both directions.  Each client can provide services to, or request services from, another client.  Napster was a very famous peer-to-peer application.\n<\/p>\n<p>\nNetPaste is much simpler than Napster.  It also avoids the dubious legal status.  NetPaste connects two computers and allows them to paste strings to each other&#8217;s clipboards.\n<\/p>\n<p>\nThis sample is a Java client application written using Java Swing.  It should run on Windows, Linux, MacOS, and any other platform where Java is available.  This application requires a Java Development Kit version 1.5 or greater.  If you don&#8217;t have JDK 1.5 you can download it from <a href=\"http:\/\/www.javasoft.com\">http:\/\/www.javasoft.com<\/a>.\n<\/p>\n<p>\nThe code in this application is free and is released under the <a href=\"http:\/\/www.apache.org\/licenses\/LICENSE-2.0\">Apache 2.0 license<\/a>.  That means you are welcome to use, copy, and change this code as much as you would like. If you find any bugs, have any comments, or make any improvements I would love to hear from you.  Other programs are needed to run this application.  They are all free, but some of them use different licenses.  You should make sure to read and understand each license before using a product.\n<\/p>\n<h2>Setup<\/h2>\n<div class=\"sourcebox\">\nGet the <br \/><a href=\"http:\/\/zackgrossbart.com\/hackito\/bsamples\/netpaste.zip\">source code<\/a>\n<\/div>\n<p>\nYou should start by downloading the source code for this sample.  It can be found <a href=\"http:\/\/zackgrossbart.com\/hackito\/bsamples\/netpaste.zip\">here<\/a>.  Once you have downloaded it you can unzip it to a work directory on your computer.\n<\/p>\n<p>\nThis program has been setup to be built using <a href=\"http:\/\/ant.apache.org\/\">Apache Ant<\/a>.  Ant is a very popular tool for building Java projects.  Building this project without Ant is possible, but it can be tricky to set up.  If you don&#8217;t have Ant already you should download and install it.\n<\/p>\n<p>\nOnce you have installed Ant you can build and run the sample application by following these steps:<\/p>\n<ol>\n<li>Unzip the sample archive to a directory on your machine.<\/li>\n<li>Open a command prompt and change directories to the location you unzipped the sample to.<\/li>\n<li>Execute the command <code>ant<\/code> (you may need to provide the full path to your Ant installation).<\/li>\n<li>Copy the netpaste.jar file to another machine (you can also run it twice on the same machine).<\/li>\n<li>Execute the command <code>java -jar netpaste.jar &lt;localport&gt; &lt;remote host&gt; &lt;remoteport&gt;<\/code> to run the sample.  <\/li>\n<\/ol>\n<p>For example, to run two instances on the same machine you could use the following commands:<\/p>\n<p><code><br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;java -jar netpaste.jar 8080 localhost 8081<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;java -jar netpaste.jar 8081 localhost 8080<\/code><\/p>\n<p>This application has a deceptively simple UI.  The goal is to make this an unobtrusive as possible.  Once you have it running you can test it out by copying a string to your clipboard from another application, switching focus back to the NetPaste window, and pressing Ctrl+V.<br \/>\n<img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.zackgrossbart.com\/hackito\/wp-content\/uploads\/2007\/11\/netpasteui.gif\" alt=\"netpasteui\" title=\"netpasteui\" width=\"329\" height=\"251\" class=\"aligncenter size-full wp-image-19\" \/>\n<\/p>\n<h2>Core Technologies<\/h2>\n<p>\nThis program will use the following core technologies:<\/p>\n<ul>\n<li>Java Swing<\/li>\n<li>Java Threading<\/li>\n<li>Java IO and Sockets<\/li>\n<\/ul>\n<p>\nThis sample is a Java Swing application.  It uses very basic Swing components to render the user interface.  It also acts as a server and creates a separate thread to receive requests from another client.  To act as a server it will use Java networking in the form of sockets.  Lastly, it will send messages back and forth over those sockets using the Java IO libraries.\n<\/p>\n<h2>How It Works<\/h2>\n<p>\nThe concept behind NetPaste is very simple.  Alice and Bob each runs a copy of NetPaste.  Alice can have her copy listen on port 8080 and connect to Bob&#8217;s computer with a command like this:<\/p>\n<p><code>&nbsp;&nbsp;&nbsp;&nbsp;java -jar netpaste.jar 8080 BobsComputer 8080<\/code><\/p>\n<p>Bob will have his copy connect to Alice&#8217;s computer with a command like this:<\/p>\n<p><code>&nbsp;&nbsp;&nbsp;&nbsp;java -jar netpaste.jar 8080 AlicesComputer 8080<\/code><\/p>\n<p>Once they have each started NetPaste they can paste strings back and forth.  When Alice pastes a string her copy of NetPaste will connect to Bob&#8217;s machine and send the string to be pasted.  Bob&#8217;s NetPaste will then copy the string into Bob&#8217;s clipboard.  In this case Alice&#8217;s machine in the client and Bob&#8217;s machine is the server.  When Bob pastes a string the process will be reversed.  In that case Alice&#8217;s machine is the server and Bob&#8217;s machine is the client.\n<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.zackgrossbart.com\/hackito\/wp-content\/uploads\/2007\/11\/netpaste.gif\" alt=\"netpaste\" title=\"netpaste\" width=\"471\" height=\"167\" class=\"aligncenter size-full wp-image-20\" \/><\/p>\n<h2>Let&#8217;s Look at the Code<\/h2>\n<p>\nThe code for this application is all stored in <code>NetPaste.java<\/code>.  All of the code for the UI, the client, the server, and the communications are in this one small file.\n<\/p>\n<h3>The Server<\/h3>\n<p>\nThe server listens for connections and receives the pasted string after it is sent.  The server is implemented by a private inner class named <code>ServerThread<\/code>.  This class extends <code>java.lang.Thread<\/code> so it can be run in a separate thread within the Java Virtual Machine.  It is very important that the server runs in a background thread so the user interface can run in the foreground thread.  The reason for this will be addressed later.  The <code>ServerThread<\/code> class has only one method.  It is named <code>run<\/code>.  Here is a simplified version of that method:<\/p>\n<table class=\"code_table\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n<tr>\n<td class=\"code-outline\">\n<pre class=\"displaycode\">public void run()\r\n{\r\n    while (true) {\r\n        if (m_ss.isClosed()) {<span class=\"footnote\"><a href=\"#npnote1\">1<\/a><\/span>\r\n            return;\r\n        }\r\n\r\n        Socket sock = m_ss.accept();<span class=\"footnote\"><a href=\"#npnote2\">2<\/a><\/span>\r\n\r\n        InputStreamReader in = new InputStreamReader(sock.getInputStream(), \"UTF-8\");<span class=\"footnote\"><a href=\"#npnote3\">3<\/a><\/span>\r\n        while (true) {<span class=\"footnote\"><a href=\"#npnote4\">4<\/a><\/span>\r\n            char c;\r\n            boolean done = false;\r\n            try {\r\n                c = (char) in.read();<span class=\"footnote\"><a href=\"#npnote5\">5<\/a><\/span>\r\n            } catch (IOException e) {\r\n                System.out.println(e.getMessage());\r\n                done = true;\r\n                c = END;\r\n            }\r\n\r\n            if (c == END || c == -1) {\r\n                continue;<span class=\"footnote\"><a href=\"#npnote6\">6<\/a><\/span>\r\n            } else if (c == 65535) {\r\n                break;<span class=\"footnote\"><a href=\"#npnote7\">7<\/a><\/span>\r\n            } else {\r\n                m_string.append(c);<span class=\"footnote\"><a href=\"#npnote8\">8<\/a><\/span>\r\n            }\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<p>This method will run in a loop for as long as the application is running.  The loop will wait for a string to be sent, read that string, and start again.  The first step is to make sure the server hasn&#8217;t been stopped by another thread<span class=\"footnote\"><a name=\"npnote1\">1<\/a><\/span>.  This will happen when the application is shutting down.  The next step is to bind the server socket<span class=\"footnote\"><a name=\"npnote2\">2<\/a><\/span>.  We have already created a <code>java.net.ServerSocket<\/code> object earlier in the code so all we need to do is tell it to start accepting connections.  When it starts accepting connections it will return a <code>java.net.Socket<\/code> object we can get information from.\n<\/p>\n<p>\nNow that the socket has been created we must read from it.  In order to do that we will create a reader<span class=\"footnote\"><a name=\"npnote3\">3<\/a><\/span>.  It is important that we create a reader rather than an input stream since we want to support pasting in multiple languages.  If we just used a stream then this application would only support English characters.  We will specify the encoding UTF-8.  UTF-8 is included with Java and it supports serializing non-English characters.\n<\/p>\n<p>\nOnce we have the stream we are ready to read the characters from it.  We don&#8217;t know how many characters there will be, so we will use a second loop to keep reading until we force it to stop<span class=\"footnote\"><a name=\"npnote4\">4<\/a><\/span>.  And then we wait<span class=\"footnote\"><a name=\"npnote5\">5<\/a><\/span>.  When the thread attempts to read a character from the socket&#8217;s reader it will pause until a character is received.  This is the reason we need a second thread.  If this happened in the UI thread then the UI would stop functioning.  Once a character comes in we need to figure out what type of character it is.  There are special characters which tell us if the specific string is finished<span class=\"footnote\"><a name=\"npnote6\">6<\/a><\/span> or if the stream has been closed from the other computer<span class=\"footnote\"><a name=\"npnote7\">7<\/a><\/span>.  All other characters are part of the pasted string<span class=\"footnote\"><a name=\"npnote8\">8<\/a><\/span>.  You can find the full implementation of this method including error handling in the source code.\n<\/p>\n<h3>The Client<\/h3>\n<p>The client portion of this program handles sending the pasted string to the server part of the program running on a different computer.  This happens in the <code>doPaste<\/code> method.  Here is a simplified version of that method.<\/p>\n<table class=\"code_table\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n<tr>\n<td class=\"code-outline\">\n<pre class=\"displaycode\">private void doPaste()\r\n{\r\n    String s = getClipboard();<span class=\"footnote\"><a href=\"#npnote9\">1<\/a><\/span>\r\n\r\n    if (!m_hasConnected) {\r\n        Socket sock = new Socket(m_host, m_port);<span class=\"footnote\"><a href=\"#npnote10\">2<\/a><\/span>\r\n        m_out = new OutputStreamWriter(sock.getOutputStream(), \"UTF-8\");<span class=\"footnote\"><a href=\"#npnote11\">3<\/a><\/span>\r\n\r\n    }\r\n\r\n    m_out.write(s);<span class=\"footnote\"><a href=\"#npnote12\">4<\/a><\/span>\r\n    m_out.write((char) END);<span class=\"footnote\"><a href=\"#npnote13\">5<\/a><\/span>\r\n    m_out.flush();<span class=\"footnote\"><a href=\"#npnote14\">6<\/a><\/span>\r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<p>The paste method has two major functions.  It will create the connection to the server, and it will send the string through that connection.  The first step is to get the string from the local clipboard<span class=\"footnote\"><a name=\"npnote9\">1<\/a><\/span>.  Once that is done we need to see if we need to create a connection<span class=\"footnote\"><a name=\"npnote10\">2<\/a><\/span> or if we can use an existing one.  After we have the new connection we can get the writer from that connection<span class=\"footnote\"><a name=\"npnote11\">3<\/a><\/span> so we can send the data.  We use a writer instead of a stream for the same reasons as in the server portion of this application:  we want to support non-English characters.  It is very important that we use the same encoding in both the server and client.  If we don&#8217;t then the characters will be corrupted.\n<\/p>\n<p>\nOnce we have the connection, sending the string is a simple process.  We just need to write out the string<span class=\"footnote\"><a name=\"npnote12\">4<\/a><\/span>, write out the special character to signify the end of the string<span class=\"footnote\"><a name=\"npnote13\">5<\/a><\/span>, and flush out the contents of the writer<span class=\"footnote\"><a name=\"npnote14\">6<\/a><\/span>.\n<\/p>\n<h3>Updating the UI<\/h3>\n<p>\nNow that we know how the data is received on the server and how the data is sent from the client the last step is to update the UI.  The server thread runs in the background and will store the data in a local variable.  The server thread can&#8217;t interact with the user and it can&#8217;t put the string in the user&#8217;s clipboard.  Both of those operations must happen in the UI thread.  The mechanism to update the UI is a timer.  A timer is a special object that causes an event to be fired at a specific time.  The timer in our application will go off every 1.5 seconds.  When it goes off it will call the <code>actionPerformed<\/code> method.  Here is a simplified version of that method.<\/p>\n<table class=\"code_table\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n<tr>\n<td class=\"code-outline\">\n<pre class=\"displaycode\">public void actionPerformed(ActionEvent e)\r\n{\r\n    if (m_string.length() == 0) {<span class=\"footnote\"><a href=\"#npnote15\">1<\/a><\/span>\r\n        return;\r\n    }\r\n\r\n    String s = null;\r\n    synchronized (m_string) {<span class=\"footnote\"><a href=\"#npnote16\">2<\/a><\/span>\r\n        s = m_string.toString();<span class=\"footnote\"><a href=\"#npnote17\">3<\/a><\/span>\r\n        m_string.delete(0, m_string.length());<span class=\"footnote\"><a href=\"#npnote18\">4<\/a><\/span>\r\n    }\r\n\r\n    if (JOptionPane.showConfirmDialog(m_main, \"Do you want to copy the string:\\n\\n\" + s) ==\r\n        JOptionPane.YES_OPTION) {<span class=\"footnote\"><a href=\"#npnote19\">5<\/a><\/span>\r\n        setClipboard(s);<span class=\"footnote\"><a href=\"#npnote20\">6<\/a><\/span>\r\n    }\r\n\r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<p>When the server receives a string it will hold it in a <code>StringBuffer<\/code>.  The first step it to look in that <code>StringBuffer<\/code> and see if there is a new string<span class=\"footnote\"><a name=\"npnote15\">1<\/a><\/span>.  Once we know there is a new string we want to copy it out so we can be sure to make space for the next string.  To do this we will use a special Java keyword called <code>synchronized<\/code><span class=\"footnote\"><a name=\"npnote16\">2<\/a><\/span>.  Once we have locked the variable we will make a copy of it<span class=\"footnote\"><a name=\"npnote17\">3<\/a><\/span>.  This will make sure that only the current thread can access that variable and ensure that the server thread doesn&#8217;t start writing a new string before we are done.  After we copy the string to a local variable we will clear out the shared variable so it can be used for the next string<span class=\"footnote\"><a name=\"npnote18\">4<\/a><\/span>.  <\/p>\n<p>\nAfter we have the string we want to prompt the user to see if they want to keep it<span class=\"footnote\"><a name=\"npnote19\">5<\/a><\/span>.  It could be a bit of a security problem to add a string to the clipboard without asking.  If the user does want to keep the string then all we need to do is send it to the clipboard<span class=\"footnote\"><a name=\"npnote20\">6<\/a><\/span>.<\/p>\n<h3>Why This Application Isn&#8217;t Completely Thread Safe<\/h3>\n<p>\nWhen writing code with multiple threads you always need to be careful about thread safety.  Thread safety is the practice of making sure that one thread will not overwrite or corrupt the data of another thread.  In this case we are using the <code>synchronized<\/code> keyword to make that happen.  However, there is a subtle bug in this code.  When the server thread stores the string which has come in it uses a single variable.  When it gets the next string it will simply append it to that variable.  This means there is a possibility that more than one string will get added before the timer goes off.  If this happened the two pasted strings could be concatenated into one.  <\/p>\n<p>\nIn practice this isn&#8217;t a large concern and we want to keep the code simple for this sample.  There is only one client for each server so the load will never be very high.  However, considering thread safety is always a good idea and this code is not strictly thread safe.  The solution to this problem would be to add a queue of pasted string which could be read from when the timer is called.<\/p>\n<h3>Personal Firewalls<\/h3>\n<p>\nIf you are running a personal firewall you may need to disable it or change it to allow this specific application.  You can adjust your personal firewall settings using the tools that came with your operating system.\n<\/p>\n<h2>Conclusion<\/h2>\n<p>\nThis program is a simple peer-to-peer application that serves a useful purpose.  It also provides a core understanding of network communications in Java.  This application is a framework, which could be expanded upon.  This program could be adapted to send files instead of strings.  It could provide information about a system running remotely.\n<\/p>\n<p>\nThe samples in this article are simplified versions of the actual source code.  The source code contains examples of Java Swing UI, reading and writing from a clipboard, listening for keyboard events, using mouse movements to move the application window, and using properties to store application state.  Please take a look at the source code for more information and more comments.\n<\/p>\n<p><\/p>\n<p>Part of the image in this document was made using an image by Dr. E.F. Tymac.  That image and the resulting image are both licensed under the <a href=\"http:\/\/creativecommons.org\/licenses\/by-sa\/2.5\/\">Creative Commons Attribution-ShareAlike 2.5 License<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I often work with two computers simultaneously. Each of those computers runs a different operating system. That work often includes the need send long strings (like long URLs) from one computer to the other. It isn&#8217;t easy. I have seen all kinds of solutions to this problem including emailing the strings back and forth or [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24,9,12],"tags":[],"_links":{"self":[{"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/posts\/9"}],"collection":[{"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/comments?post=9"}],"version-history":[{"count":2,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/posts\/9\/revisions"}],"predecessor-version":[{"id":351,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/posts\/9\/revisions\/351"}],"wp:attachment":[{"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/media?parent=9"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/categories?post=9"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/tags?post=9"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}