Java 使用单个TCP/IP套接字从多个并发线程发送数据时出现问题

Java 使用单个TCP/IP套接字从多个并发线程发送数据时出现问题,java,multithreading,sockets,tcp,Java,Multithreading,Sockets,Tcp,在浏览了一些关于我的问题的其他线程之后,我想我已经明白我需要重新设计我的应用程序。但只是为了澄清一下:我在客户端和服务器之间有一个TCP/IP连接。在客户端,有许多线程同时运行。随机地,其中一个或多个线程使用TCP/IP连接与服务器通信。我发现了,e。G当长时间运行的文件传输处于活动状态时,同时使用与另一个线程的连接可能会导致错误。虽然我在每条消息之前都有一个特定的头,包括数据长度,但在我看来,IP堆栈有时会向我的程序发送多条消息,这意味着尽管一条消息尚未完全发送,但另一条消息的一部分会发送到我

在浏览了一些关于我的问题的其他线程之后,我想我已经明白我需要重新设计我的应用程序。但只是为了澄清一下:我在客户端和服务器之间有一个
TCP/IP
连接。在客户端,有许多线程同时运行。随机地,其中一个或多个线程使用
TCP/IP
连接与服务器通信。我发现了,e。G当长时间运行的文件传输处于活动状态时,同时使用与另一个线程的连接可能会导致错误。虽然我在每条消息之前都有一个特定的头,包括数据长度,但在我看来,
IP
堆栈有时会向我的程序发送多条消息,这意味着尽管一条消息尚未完全发送,但另一条消息的一部分会发送到我的读取方法。这是否符合预期的
TCP/IP
行为的正确观察结果?提前谢谢-马里奥

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

对于任何感兴趣的人:以下是我的测试程序的源代码。您可以使用不同的缓冲区大小值和线程数来使用同一套接字通过并发TCP/IP发送轰击服务器套接字。我省略了一些错误处理,删除了一个更复杂的终端,包括关闭插座。缓冲区大小大于64KB的测试总是导致我的计算机出错

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 => 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 < 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 < iLength) && (BUFFER_SIZE >= iLength))
            {
              // that's the case => read complete message
              while (iLengthSoFar < iLength)
              {
                // calculate number of bytes left
                iBytesLeft = iLength - iLengthSoFar;
                 // calculate maximum number of bytes to read
                if (iBytesLeft > 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 => print message
                  System.out.println("==> "+id+": ERROR length=<-1> received " +
                        "for id=<"+iId+">");
                  fTerminate = true;
                  break;
                } // else
              } // while
            } // if
            else
            {
              System.out.println("==> "+id+": ERROR data length <= 0 for id=<"+iId+">");
              dump(header, 0, HEADER_SIZE / SIZE_OF_INT, "Error header");
            } // else
          } // while
          System.out.println("==> "+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("==> "+id+": just awoke");
      Socket       socket             = new Socket("localhost", 12345);
      OutputStream socketOutputStream = socket.getOutputStream();
      System.out.println("==> "+id+": socket obtained");
      // create some writer threads
      for (int i = 0; i < 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 < 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("==> "+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 <= iTotalBytesRead)
          {
            System.out.println("==> "+m_id+": <"+iTotalBytesRead+"> bytes processed");
            iNextMessageSize += MESSAGE_SIZE;
          } // if
        } // while
        // close my file input stream
        fileInputStream.close();
        System.out.println("==> "+m_id+": file input stream closed");
        System.out.println("==> "+m_id+": <"+ iTotalBytesRead + "> bytes written in " 
                            + (System.currentTimeMillis() - startTime) + " ms.");
        // decrement thread counter
        synchronized (m_serverSocket)
        {
          m_iThreadCounter--;
          // last thread?
          if (0 >= m_iThreadCounter)
            // that's the case => terminate
            System.exit(0);
        } // synchronized
      } // try 
      catch (Exception e) 
      {
        e.printStackTrace();
      } // catch
    } // run
  } // SocketWriter
} // TCPTest
import java.io.*;
导入java.net。*;
导入java.nio.ByteBuffer;
公共类测试
{
私有最终静态字符串输入\u FILE=“c:/temp/tcptest.in”;
私有最终静态int缓冲区_SIZE=64*1024-8;//65536;
私有最终静态整型消息_SIZE=512*64*1024;
私有最终静态int线程=3;
私有最终静态整数大小为4;
私有最终静态整数长度\u SIZE=整数的大小;
私有最终静态整数ID\u SIZE=整数的大小;
私有最终静态整数头大小=长度大小+ID大小;
私有最终静态字符串NEW_LINE=System.getProperty(“LINE.separator”);
私有服务器套接字m_ServerSocket=null;
私有套接字m_clientSocket=null;
私人国际货币兑换柜台;
公共静态void main(字符串[]args)
{
新TCPTest();
}//主要
公共TCPTest()
{
最终字符串id=“ReaderThread[*]”;
//启动一个新线程,创建一个等待连接的服务器套接字
新线程(newrunnable())
{
公开募捐
{
尝试
{
//创建服务器套接字并接受客户端请求
m_serverSocket=新的serverSocket(12345);
m_clientSocket=m_serverSocket.accept();
//客户端请求=>准备和读取数据
long startTime=System.currentTimeMillis();
字节[]缓冲区=新字节[缓冲区大小];
ByteBuffer头=ByteBuffer.allocate(头大小);
int-iTotalBytesRead=0;
布尔fTerminate=false;
内部iBytesRead;
//获取套接字的输入流
InputStream clientInputStream=m_clientSocket.getInputStream();
//环路
while(false==fTerminate)
{
//循环以读取下一个标题
对于(int i=0;i=iLength))
{
//就是这样=>阅读完整的消息
while(iLengthSoFar缓冲区大小)
iBytesToRead=缓冲区大小;
其他的
iBytesToRead=iBytesLeft;
//读取字节的下一部分
if((iBytesRead=clientInputStream.read(缓冲区,0,iBytesToRead))!=-1)
{
//维护统计数据
iTotalBytesRead+=iBytesRead;
iLengthSoFar+=Ibytes读取;
}//如果
其他的
{
//完成=>打印消息
System.out.println(“==>”+id+”:错误长度=已接收”+
“for id=”);
fTerminate=true;
打破
}//否则
}//而
}//如果
其他的
{
System.out.println(“==>”+id+”:错误数据长度“+id+”:“+iTotalBytesRead+”字节读入”
+(System.currentTimeMillis()-startTime)+“ms.”;
}//试试看
捕获(IOE异常)
{
e、 printStackTrace();
}//抓住
}//运行
}).start();
//创建套接字编写器线程
尝试
{
//确保启动服务器并请求连接
睡眠(1000);
System.out.println(“==>”+id+“:刚刚醒来”);
套接字=新套接字(“localhost”,12345);
OutputStream socketOutputStream=socket.getOutputStream();
System.out.println(“==>”+id+“:获得套接字”);
//创建一些writer线程
对于(int i=0;i