Java 可靠的UDP算法实现
这是我第一次在这个网站上问一些问题。如果有什么错误,请对我温柔一点 我正在尝试使用UDP编写“可靠”的文件传输。 其思想是服务器将文件拆分为多个部分。每个部分包含许多数据包。Java 可靠的UDP算法实现,java,Java,这是我第一次在这个网站上问一些问题。如果有什么错误,请对我温柔一点 我正在尝试使用UDP编写“可靠”的文件传输。 其思想是服务器将文件拆分为多个部分。每个部分包含许多数据包。 服务器尝试在一个部分发送所有数据包,并等待客户端响应。 客户端接收数据包并检查是否有丢失的数据包。如果是,则向服务器发送响应,并告知丢失的数据包。 服务器从客户端接收响应并重新发送丢失的数据包。 如果没有数据包丢失,服务器将切换到下一部分并继续,直到结束 这就是想法,这是实际的代码 public void Send() t
服务器尝试在一个部分发送所有数据包,并等待客户端响应。
客户端接收数据包并检查是否有丢失的数据包。如果是,则向服务器发送响应,并告知丢失的数据包。
服务器从客户端接收响应并重新发送丢失的数据包。
如果没有数据包丢失,服务器将切换到下一部分并继续,直到结束 这就是想法,这是实际的代码
public void Send() throws IOException, InterruptedException, ClassNotFoundException {
DatagramSocket ds = new DatagramSocket(4567);
File file = new File("D:\\DOWNLOAD\\HC.flac");
FileInputStream f = new FileInputStream(file);
byte[] b = new byte[10000];
//calculate file length
int remainLength = (int) file.length();
//calculate total packet will be sent
ByteBuffer bbuf = ByteBuffer.allocate(4);
int totalPacket = remainLength / 10000 + 1;
bbuf.putInt(totalPacket);
byte[] result = bbuf.array();
//send total packet to client
DatagramPacket total_Packet = new DatagramPacket(result,result.length,InetAddress.getByName("192.168.1.5"), 4567);
ds.send(total_Packet);
//position of packet is being sent (in total packets)
int packetNumber = 0;
TimeUnit.MILLISECONDS.sleep(1);
try {
while (remainLength != 0) {
//create an array of packet, the client has a same array
//this array is in order to make all receive packet (on client) is in order and check if there is any lost packet
PacketSend[] windowBuffer = new PacketSend[1000];
//position of packet is being sent (in windowBuffer)
int windowIndex = 0;
//this while loop assign packet into windowBuffer
while (remainLength >= 10000) {
//read file
b = new byte[10000];
f.read(b, 0, 10000);
//create packet with its position
PacketSend fs = new PacketSend(packetNumber,windowIndex, b);
//assign packet into window
windowBuffer[windowIndex] = fs;
//subtract the remaining length of file by 10000 (1 packet hold 10000 byte data of the file)
remainLength = remainLength - 10000;
packetNumber++;
//if windowIndex = 999, that means the windowBuffer hold full of packet, ready to send to client
if (windowIndex == 999)
break;
windowIndex++;
}
//if this is the last packet
if (remainLength > 0 && remainLength < 10000) {
//only read the remaining
b = new byte[remainLength];
int read = f.read(b, 0, remainLength);
PacketSend fs = new PacketSend(packetNumber,windowIndex, b);
windowBuffer[windowIndex] = fs;
remainLength = 0;
}
//this for loop send all the packet in windowBuffer to client
for (int j = 0; j <= windowIndex; j++) {
//serialize packet before send
ByteArrayOutputStream bStream = new ByteArrayOutputStream(
10076);
ObjectOutput oos = new ObjectOutputStream(bStream);
oos.writeObject(windowBuffer[j]);
oos.close();
byte[] serialize = new byte[10076];
serialize = bStream.toByteArray();
//send packet to client
DatagramPacket dp = new DatagramPacket(serialize,
serialize.length,
InetAddress.getByName("192.168.1.5"), 4567);
System.out.println("Sending " + serialize.length
+ " bytes to client, port 4567, packet: "
+ windowBuffer[j].packetNumber);
ds.send(dp);
//remove this line make the program always fail (because to many packets lost and it is easier for you to know what problem I am asking)
//if this line exist, the program sometimes fail, sometimes work and I dont know why
TimeUnit.MILLISECONDS.sleep(1);
}
//ds.setSoTimeout(2500);
//when all packets in windowBuffer are sent to client
//this while loop handle the lost packets
while(true){
byte[] requestedPacket = new byte[10000];
DatagramPacket dp = new DatagramPacket(requestedPacket,
requestedPacket.length);
try{
//the server stop and wait for response from client
//sometimes it just stop at there
//I know UDP is unreliable, so the response from client may get lost, but I made the client resend its response to make sure server received
//but it sometimes just stuck forever
//Here is the problem I am asking
ds.receive(dp);
}
catch (SocketTimeoutException ste){
ds.close();
break;
}
//deserialize the response from client
ObjectInputStream iStream = new ObjectInputStream(
new ByteArrayInputStream(requestedPacket));
ArrayList<Integer> missingPacket = new ArrayList<Integer>();
//The response from client is an array of lost packets position (in windowBuffer)
missingPacket = (ArrayList<Integer>) iStream.readObject();
//if there is no lost packet, break this while loop
//it mean move the windowBuffer to the next part of the file
//the client move its windowBuffer too
if (missingPacket.size() == 0){
break;
}
System.out.printf("Resending %d missing packet.\n",missingPacket.size());
//resend those lost packets
//all the packets is still hold in windowBuffer, if you know which packet is missing, just resend them.
for (int i = 0; i < missingPacket.size(); i++){
//serialize
ByteArrayOutputStream bStream = new ByteArrayOutputStream(
10076);
ObjectOutput oos = new ObjectOutputStream(bStream);
oos.writeObject(windowBuffer[missingPacket.get(i)]);
oos.close();
byte[] serialize = new byte[10076];
serialize = bStream.toByteArray();
//and send
DatagramPacket dtp = new DatagramPacket(serialize,
serialize.length,
InetAddress.getByName("192.168.1.5"), 4567);
System.out.println("Sending " + serialize.length
+ " bytes to client, port 4567, packet: "
+ windowBuffer[missingPacket.get(i)].packetNumber);
ds.send(dtp);
TimeUnit.MILLISECONDS.sleep(1);
}
}
//--------------------------------------------
//ket thuc xu ly mat goi tin
}
System.out.println("File Transfer completed !!");
} catch (FileNotFoundException ex) {
System.out.println("File not found :P");
}
finally {
f.close();
}
}
但有时程序可以运行,有时会失败。它在服务器停止并等待客户端响应的线路上失败。客户端尝试将响应重新发送到服务器,但服务器似乎没有收到任何响应
当我尝试使用这些代码来制作多线程GUI程序时,问题会变得更糟。它每次都卡在那条线上
我在real machine中运行服务器,在vmware中运行客户端,两者都连接到real LAN路由器
如果有人知道问题的原因,请告诉我。尽可能简单地解释,因为我不会说英语
多谢各位 为什么要使用UDP?为什么不是TCP?TCP通过内置ACK提供可靠的传递。不清楚您为什么要这样做,而不仅仅是使用TCP。您可能有XY问题。请详细说明。我知道TCP更好,但使用UDP是一项要求。任何人都想知道我为什么不使用TCP。因为这是深入理解TCP工作原理的一个家庭作业。实际上,我尝试用“更简单”的方法模拟选择性重复滑动窗口协议(我认为)。我尝试使滑动窗口只在固定位置移动,而不是像选择性重复滑动窗口协议那样移动。当它失败时,您能添加准确的错误消息吗?此外,您是否创建了它始终失败或通过的场景?你能描述这样的场景吗(在哪里失败,在哪里通过)?
public void Receive() throws IOException, ClassNotFoundException, InterruptedException {
DatagramSocket ds = new DatagramSocket(4567);
try {
byte[] receiveData = new byte[10103];
byte[] receiveNumPacket = new byte[4];
FileOutputStream fos = new FileOutputStream(new File("C:\\Users\\TESTED\\Desktop\\abc\\test.mp3" + ""));
{
ds.setSoTimeout(10000);
//receive total packets number from server
DatagramPacket p = new DatagramPacket(receiveNumPacket, receiveNumPacket.length);
ds.receive(p);
}
//calculate number of total packet from byte array
ByteBuffer bb = ByteBuffer.wrap(receiveNumPacket);
int totalPacket = bb.getInt();
int windowSize = 1000;
//set the timeout
//if the timeout passed, it mean the server sent all its packet in windowBuffer and waiting for response
ds.setSoTimeout(500);
Outer: while (totalPacket > 0) {
PacketSend[] windowBuffer = new PacketSend[1000];
Inner: while (true) {
try {
receiveData = new byte[10103];
DatagramPacket dp = new DatagramPacket(receiveData, receiveData.length);
//receive data from server
//if this packet lost, the program should fail. This is not the problem I'm asking
ds.receive(dp);
byte[] b1 = new byte[dp.getLength()];
//deserialize
ObjectInputStream iStream = new ObjectInputStream(new ByteArrayInputStream(receiveData));
PacketSend fr = new PacketSend();
//assign the receive packet to windowBuffer
fr = (PacketSend) iStream.readObject();
windowBuffer[fr.bufferIndex] = fr;
iStream.close();
System.out.printf("Receive packet number: %d \n", fr.packetNumber);
//timeout passed, it mean the server sent all its packet in windowBuffer and waiting for response
} catch (SocketTimeoutException ste) {
while (true) {
//check if this is the last part of the file
if (totalPacket < 1000)
windowSize = totalPacket;
//check if there is any packet lost
//those lost packets position will be hold in missingPacket array
ArrayList<Integer> missingPacket = new ArrayList<Integer>();
for (int i = 0; i < windowSize; i++) {
if (windowBuffer[i] == null) {
missingPacket.add(i);
}
}
//if there is any lost packet
if (missingPacket.size() != 0) {
//serialize missingPacket array
ByteArrayOutputStream bStream = new ByteArrayOutputStream(10000);
ObjectOutput oos = new ObjectOutputStream(bStream);
oos.writeObject(missingPacket);
oos.close();
byte[] serialize = new byte[10000];
serialize = bStream.toByteArray();
DatagramPacket dp = new DatagramPacket(serialize, serialize.length,
InetAddress.getByName("192.168.1.2"), 4567);
System.out.println("Request missing packet " + serialize.length
+ " bytes to server, port 4567, number of lost packets: "
+ missingPacket.size());
//send response to server, let it know which packet is lost
ds.send(dp);
TimeUnit.MILLISECONDS.sleep(1);
//continue inner loop
//it mean try to receive packet from server and do the check
continue Inner;
}
//if all packet in windowBuffer received
ByteArrayOutputStream bStream = new ByteArrayOutputStream(10000);
ObjectOutput oos = new ObjectOutputStream(bStream);
oos.writeObject(missingPacket);
oos.close();
byte[] serialize = new byte[10000];
serialize = bStream.toByteArray();
DatagramPacket dp = new DatagramPacket(serialize, serialize.length,
InetAddress.getByName("192.168.1.2"), 4567);
System.out.println("Notice server all packet received");
//send response to server
//but this time, the missingPacket array have no member
//this also the sign for the server know it's time for move its windowBuffer to new position
ds.send(dp);
totalPacket -= 1000;
//write file to disk
for (int i = 0; i < windowSize; i++) {
fos.write(windowBuffer[i].data, 0, windowBuffer[i].data.length);
}
//continue the outer loops
//it mean move windowBuffer to new position
continue Outer;
}
}
}
}
fos.close();
System.out.println("File Transfer completed !!");
} catch (SocketException ex) {
System.out.println("UDP Port is occupied.");
System.exit(1);
}
}
public int packetNumber;
public int bufferIndex;
public byte[] data = new byte[1024];
public PacketSend(int _packetNumber,int _indexInBuffer,byte[] _data)
{
packetNumber = _packetNumber;
bufferIndex = _indexInBuffer;
data = _data;
}
public PacketSend(){}
public PacketSend(PacketSend fs)
{
packetNumber = fs.packetNumber;
bufferIndex = fs.bufferIndex;
data = fs.data;
}