title: Problems using single TCP/IP socket to send data from multiple concurrent threads
body: <p>After browsing some other threads regarding my problem I think I've understood that I need to re-design my application. But just for clarification: I have a single <code>TCP/IP</code> connection between a client and a server. On the client side there are a number of threads running concurrently. Randomly one or more of these threads use the <code>TCP/IP</code> connection to communicate with the server. I've found out that, e. g. While a long running file transfer is active, using the connection with another thread concurrently might lead to errors. Though I've preceeded each message with a specific header including the data length it appears to me that the <code>IP</code> stack sometimes delivers a mix of more than one messages to my program, which means that though one message has net yet been delivered completely, part of another message is delivered to my read method. Is this a correct observation which matches the intended <code>TCP/IP</code> behaviour? Thanks in advance - Mario</p>
  
  <p>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</p>
  
  <p>For anybody who's interested: following is the source code of my test program. You may play with various values for the BUFFER_SIZE and the number of THREADS used to bombard the server socket with concurrent TCP/IP sends using the same socket. I've left out some error handling and removed a more sophisticated termination including the closing of the sockets. Test with a BUFFER_SIZE greater than 64KB always leads to errors on my machine.</p>
  
  <pre><code>import java.io.*;
  import java.net.*;
  import java.nio.ByteBuffer;
  
  public class TCPTest
  {
    private final static String INPUT_FILE   = "c:/temp/tcptest.in";
    private final static int    BUFFER_SIZE  = 64 * 1024 - 8; //65536;
    private final static int    MESSAGE_SIZE = 512 * 64 * 1024;
    private final static int    THREADS      = 3;
    private final static int    SIZE_OF_INT  = 4;
    private final static int    LENGTH_SIZE  = SIZE_OF_INT;
    private final static int    ID_SIZE      = SIZE_OF_INT;
    private final static int    HEADER_SIZE  = LENGTH_SIZE + ID_SIZE;
    private final static String NEW_LINE     = System.getProperty("line.separator");
  
    private ServerSocket m_serverSocket = null;
    private Socket       m_clientSocket = null;
    private int          m_iThreadCounter;
  
    public static void main(String[] args)  
    {
      new TCPTest();
    } // main
  
    public TCPTest() 
    {
      final String id = "ReaderThread[*]";
      // start a new thread creating a server socket waiting for connections 
      new Thread(new Runnable() 
      {
        public void run() 
        {
          try 
          {
            // create server socket and accept client requests
            m_serverSocket = new ServerSocket(12345);
            m_clientSocket = m_serverSocket.accept();
            // client request =&gt; prepare and read data
            long       startTime       = System.currentTimeMillis();
            byte[]     buffer          = new byte[BUFFER_SIZE];
            ByteBuffer header          = ByteBuffer.allocate(HEADER_SIZE);
            int        iTotalBytesRead = 0;
            boolean    fTerminate      = false;
            int        iBytesRead;
            // get hold of socket's input stream
            InputStream clientInputStream = m_clientSocket.getInputStream();
            // loop
            while (false == fTerminate)
            {
              // loop to read next header
              for (int i = 0; i &lt; HEADER_SIZE; i++)
                clientInputStream.read(header.array(), i, 1);
              header.rewind();
              // get information of interest
              int iLength      = header.getInt();
              int iId          = header.getInt();
              int iLengthSoFar = 0;
              int iBytesLeft   = iLength;
              int iBytesToRead;
              // any length given?
              if ((0 &lt; iLength) &amp;&amp; (BUFFER_SIZE &gt;= iLength))
              {
                // that's the case =&gt; read complete message
                while (iLengthSoFar &lt; iLength)
                {
                  // calculate number of bytes left
                  iBytesLeft = iLength - iLengthSoFar;
                   // calculate maximum number of bytes to read
                  if (iBytesLeft &gt; BUFFER_SIZE)
                    iBytesToRead = BUFFER_SIZE;
                  else
                    iBytesToRead = iBytesLeft;
                  // read next portion of bytes
                  if ((iBytesRead = clientInputStream.read(buffer, 0, iBytesToRead)) != -1)
                  {
                    // maintain statistics
                    iTotalBytesRead += iBytesRead;
                    iLengthSoFar += iBytesRead;
                  } // if
                  else
                  {
                    // finish =&gt; print message
                    System.out.println("==&gt; "+id+": ERROR length=&lt;-1&gt; received " +
                          "for id=&lt;"+iId+"&gt;");
                    fTerminate = true;
                    break;
                  } // else
                } // while
              } // if
              else
              {
                System.out.println("==&gt; "+id+": ERROR data length &lt;= 0 for id=&lt;"+iId+"&gt;");
                dump(header, 0, HEADER_SIZE / SIZE_OF_INT, "Error header");
              } // else
            } // while
            System.out.println("==&gt; "+id+": "+ iTotalBytesRead + " bytes read in " 
                                + (System.currentTimeMillis() - startTime) + " ms.");
          } // try 
          catch (IOException e) 
          {
            e.printStackTrace();
          } // catch
        } // run
      }).start();
      // create the socket writer threads
      try
      {
        // ensure server is brought up and request a connection
        Thread.sleep(1000);
        System.out.println("==&gt; "+id+": just awoke");
        Socket       socket             = new Socket("localhost", 12345);
        OutputStream socketOutputStream = socket.getOutputStream();
        System.out.println("==&gt; "+id+": socket obtained");
        // create some writer threads
        for (int i = 0; i &lt; THREADS; i++)
          // create a new socket writer and start the thread
          (new SocketWriter(socket, 
                            (i+1),
                            BUFFER_SIZE,
                            new String("WriterThread["+(i+1)+"]"),
                            socketOutputStream)).start();
      } // try
      catch (Exception e)
      {
        e.printStackTrace();
      } // catch
    } // TCPTestEx
  
    private final static void dump(ByteBuffer bb, int iOffset, int iInts, String header)
    {
      System.out.println(header);
      bb.rewind();
      for (int i = 0; i &lt; iInts; i++)
        System.out.print(" " + Integer.toHexString(bb.getInt()).toUpperCase());
      System.out.print(NEW_LINE);
    } // dump
  
    private class SocketWriter extends Thread
    {
      Socket       m_socket;
      int          m_iId;
      int          m_iBufferSize;
      String       m_id;
      OutputStream m_os;
  
      protected SocketWriter(Socket socket, int iId, int iBufferSize, String id, OutputStream os)
      {
        m_socket       = socket;
        m_iId          = iId;
        m_iBufferSize  = iBufferSize;
        m_id           = id;
        m_os           = os;
        // increment thread counter
        synchronized (m_serverSocket)
        {
          m_iThreadCounter++;
        } // synchronized
      } // SocketWriter
  
      public final void run()
      {
        try 
        {
          long       startTime        = System.currentTimeMillis();
          ByteBuffer buffer           = ByteBuffer.allocate(m_iBufferSize + HEADER_SIZE); 
          int        iTotalBytesRead  = 0;
          int        iNextMessageSize = 512 * m_iBufferSize; 
          int        iBytesRead;
          // open input stream for file to read and send
          FileInputStream fileInputStream = new FileInputStream(INPUT_FILE);
          System.out.println("==&gt; "+m_id+": file input stream obtained");
          // loop to read complete file
          while (-1 != (iBytesRead = fileInputStream.read(buffer.array(), HEADER_SIZE, m_iBufferSize))) 
          {
            // add length and id to buffer and write over TCP
            buffer.putInt(0, iBytesRead);
            buffer.putInt(LENGTH_SIZE, m_iId);
            m_os.write(buffer.array(), 0, HEADER_SIZE + iBytesRead);
            // maintain statistics and print message if so desired
            iTotalBytesRead += iBytesRead;
            if (iNextMessageSize &lt;= iTotalBytesRead)
            {
              System.out.println("==&gt; "+m_id+": &lt;"+iTotalBytesRead+"&gt; bytes processed");
              iNextMessageSize += MESSAGE_SIZE;
            } // if
          } // while
          // close my file input stream
          fileInputStream.close();
          System.out.println("==&gt; "+m_id+": file input stream closed");
          System.out.println("==&gt; "+m_id+": &lt;"+ iTotalBytesRead + "&gt; bytes written in " 
                              + (System.currentTimeMillis() - startTime) + " ms.");
          // decrement thread counter
          synchronized (m_serverSocket)
          {
            m_iThreadCounter--;
            // last thread?
            if (0 &gt;= m_iThreadCounter)
              // that's the case =&gt; terminate
              System.exit(0);
          } // synchronized
        } // try 
        catch (Exception e) 
        {
          e.printStackTrace();
        } // catch
      } // run
    } // SocketWriter
  } // TCPTest
  </code></pre>