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