title: Tweaking performance of Java's sockets
body: <p>I've created a remote desktop control application. Obviously, it consists of client and server parts:</p>
  
  <p><strong>Server:</strong></p>
  
  <ul>
  <li>Receiving mouse/keyboard actions from client;</li>
  <li>Sending screenshot of desktop to client.</li>
  </ul>
  
  <p><strong>Client:</strong></p>
  
  <ul>
  <li>Receiving screenshot from server;</li>
  <li>Sending mouse/keyboard actions;</li>
  </ul>
  
  <p>Consider sending the screenshot. When I use my home PC as a server - I end up with a 1920x1080 screenshot dimension. By using <a href="http://download.java.net/media/jai-imageio/builds/release/1.1/" rel="noreferrer">JAI Image I/O Tools</a> and encoding it as PNG I was able to achieve the following stats for such a big image:</p>
  
  <ol>
  <li>Write time ~0.2 s; (not into socket, but into some "regular" output stream, <strong>i. e. encode time</strong>)</li>
  <li>Read time ~0.05 s; (not from socket, but from some "regular" input stream, <strong>i. e. decode time</strong>)</li>
  <li>Size ~250 KB;</li>
  <li>Perfect quality.</li>
  </ol>
  
  <p>As a result, according to #1 - the ideal possible FPS should be ~5.</p>
  
  <p>Unfortunately, I'm not able to achieve even those ~5 FPS, not even 2 FPS. I searched for the bottleneck and found out that writing/reading to/from <strong>socket I/O streams</strong> takes up to ~2 s (<strong>See appendix 1 and 2 for clarification</strong>). Surely that is unacceptable.</p>
  
  <p>I've researched the topic a bit - and added buffering of socket's I/O streams (with <code>BufferedInputStream</code> and <code>BufferedOutputStream</code>) on both sides. I've started with 64 KB sizes. This indeed improved performance. But still can't have at least 2 FPS! In addition, I've experimented with <code>Socket#setReceiveBufferSize</code> and <code>Socket#setSendBufferSize</code> and there were some changes in speed, but I don't know how exactly they behave, therefore I don't know which values to use.</p>
  
  <p>Look at initialization code:</p>
  
  <p><strong>Server:</strong></p>
  
  <pre><code>    ServerSocket serverSocket = new ServerSocket();
      serverSocket.setReceiveBufferSize( ? ); // #1
      serverSocket.bind(new InetSocketAddress(...));
  
      Socket clientSocket = serverSocket.accept();
      clientSocket.setSendBufferSize( ? ); // #2
      clientSocket.setReceiveBufferSize( ? ); // #3
  
      OutputStream outputStream = new BufferedOutputStream(
              clientSocket.getOutputStream(), ? ); // #4
      InputStream inputStream = new BufferedInputStream(
              clientSocket.getInputStream(), ? ); // #5
  </code></pre>
  
  <p><strong>Client:</strong></p>
  
  <pre><code>    Socket socket = new Socket(...);
      socket.setSendBufferSize( ? ); // #6
      socket.setReceiveBufferSize( ? ); // #7
  
      OutputStream outputStream = new BufferedOutputStream(
              socket.getOutputStream(), ? ); // #8
      InputStream inputStream = new BufferedInputStream(
              socket.getInputStream(), ? ); // #9
  </code></pre>
  
  <p><strong>Questions:</strong></p>
  
  <ol>
  <li>Which values would you recommend (to improve performance) for all
  these cases and why?</li>
  <li>Please clarify <code>Socket#setReceiveBufferSize</code> and
  <code>Socket#setSendBufferSize</code> behavior.</li>
  <li>What other methods/techniques can you advise to improve performance
  of such application?</li>
  <li>Skype provides good-quality real-time desktop transmission - how do they do it?</li>
  </ol>
  
  <p><strong>Appendix 1:</strong> Adding the unrolled pseudo-code of client socket reading (@mcfinnigan):</p>
  
  <pre><code>while(true) {
      // objectInputStream is wrapping socket's buffered input stream.
      Object object = objectInputStream.readObject(); // &lt;--- Bottleneck (without setting proper buffer sizes is ~2 s)
  
      if(object == null)
          continue;
  
      if(object.getClass() == ImageCapsule.class) {
          ImageCapsule imageCapsule = (ImageCapsule)object;
  
          screen = imageCapsule.read(); // &lt;--- Decode PNG (~0.05 s)
  
          SwingUtilities.invokeLater(new Runnable() {
              @Override
              public void run() {
                  repaint();
              }
          });
      }
  }
  </code></pre>
  
  <p><strong>Appendix 2:</strong> Adding the unrolled pseudo-code of server socket writing (@EJP):</p>
  
  <pre><code>while(true) {
      // objectOutputStream is wrapping socket's buffered output stream.
      BufferedImage screen = ... // obtaining screenshot
      ImageCapsule imageCapsule = new ImageCapsule();
  
      imageCapsule.write(screen, formatName()); // &lt;--- Encode PNG (~0.2 s)
  
      try {
          objectOutputStream.writeObject(imageCapsule); // &lt;--- Bottleneck (without setting proper buffer sizes is ~2 s)
      }
      finally {
          objectOutputStream.flush();
          objectOutputStream.reset(); // Reset to free written objects.
      }
  }
  </code></pre>
  
  <p><strong>Conclusion:</strong></p>
  
  <p>Thanks for your answers, specially EJP - he made things a bit more clear to me. If you are like me - seeking answers on how to tweak sockets' performance you should definitely check <a href="https://rads.stackoverflow.com/amzn/click/com/0123742552" rel="noreferrer" rel="nofollow noreferrer">TCP/IP Sockets in Java, Second Edition: Practical Guide for Programmers</a>, especially chapter 6 "Under the Hood" which describes what happens behind the scenes of <code>*Socket</code> classes, how send and receive buffers are managed and utilized (which are primary keys to performance).</p>