使用 UDP 逐部分发送文件
Send file part by part with UDP
我会在我的服务器端发送一个分成 N 个部分的 XML 文件。
每个文件在开始时都包含以下信息:fileNumber 和 totalPart
例如,如果我有 32 个部分:
- 第一个文件包含在开头:0(文件编号)和 32(总部分)
- 第二个文件包含在开头:1(文件编号)和 32(总部分)...
使用 for 循环,我可以同时将所有部分发送给我的客户。
但是我的客户不能收到所有的零件,我丢失了一些零件..
我该如何处理所要求的缺失零件?
这是我的服务器端代码:
for (int i = 0; i < nbPart + 1; i++) {
File f = null;
BufferedReader br = null;
String content = "";
byte[] sendBuffer = null;
try {
f = new File("xml/file.part" + i);
br = new BufferedReader(new FileReader(f));
StringBuilder sbuilder = new StringBuilder();
String line = br.readLine();
while (line != null) {
sbuilder.append(line);
line = br.readLine();
if (line != null) {
sbuilder.append("\n");
}
}
content = i + ";" + nbPart + "#tag#" + sbuilder.toString();
int total = new Long(f.length()).intValue();
sendBuffer = new byte[total];
sendBuffer = content.getBytes();
DatagramSocket sendSocket = new DatagramSocket();
DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, source, PORT_SEND);
sendSocket.send(sendPacket);
sendSocket.close();
Thread.sleep(timeToSend);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null)
br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
这是我的客户端代码:
while (run) {
DatagramSocket receiveSocket = null;
DatagramPacket receivePacket = null;
data = "";
byte[] receiveBuffer = new byte[9999];
Arrays.fill(receiveBuffer, (byte) 0);
try {
receiveSocket = new DatagramSocket(PORT_RECEIVE);
receivePacket = new DatagramPacket(receiveBuffer,receiveBuffer.length);
receiveSocket.receive(receivePacket);
receiveSocket.close();
data = new String(receiveBuffer, receivePacket.getOffset(), receivePacket.getLength());
String datas[] = data.split("#tag#");
String dataParts[] = datas[0].split(";");
int numPart = Integer.parseInt(dataParts[0]);
totalPart = Integer.parseInt(dataParts[1]);
if(partReceive.isEmpty()){
for(int i=0;i<totalPart+1;i++){
partReceive.add(Boolean.FALSE);
}
}
File part = new File(filePath+"/file.part"+numPart);
if(part.exists()) part.delete();
writeToFile(part, datas[1]);
partReceive.set(numPart, Boolean.TRUE);
Log.wtf("Part"+numPart, partReceive.get(numPart).toString());
} catch (Exception e) {
e.printStackTrace();
}
}
如您所见,我的第一个想法是:在客户端,我创建一个包含布尔值 (False) 的 ArrayList partReceive,当我收到一个部分时,我将 ArrayList 的索引设置为 "True" .但是在我如何处理之后?
我想到了两种可能的方法:
- 使用 TCP。它会自动确保按顺序接收所有数据包。
- 也许你故意想让你使用UDP。我不太明白你的 ArrayList
partReceive
的意义。循环将 alawys 将所有元素设置为 false,因为 totalPart
在整个传输过程中保持不变。在您的示例中,它将始终为 32。我宁愿为每个数据包分配一个 ID
。 ID 是唯一的编号。例如,您可以使用 numPart
。收到数据包时,将其 ID 存储在列表中。整个传输完成后,检查仍然缺少哪些 id。最简单的方法是 request each missing packet
.
类似的东西
ArrayList<Integer> receivedParts = new ArrayList<Integer>();
// save id of received packet
receivedParts.add(numPart);
// ...
// after transmission has finished
// Keep in mind that packets do not necessarily need to arrive in the same order like you've sent them when using UDP.
ArrayList<Integer> missingIDs = getMissingIDs(receivedParts);
for(Integer currentID : missingIDs) {
// request missing packets
requestMissingPacket(currentID);
}
检查传输是否完成有多种方式:
- 收到所有数据包后,传输。只需检查
receiveParts
列表的大小。
- 使用
timeout
。例如,如果您在 x 秒内没有收到任何数据包,则认为传输已完成。然后检查丢失了哪些数据包。
我会在我的服务器端发送一个分成 N 个部分的 XML 文件。
每个文件在开始时都包含以下信息:fileNumber 和 totalPart
例如,如果我有 32 个部分: - 第一个文件包含在开头:0(文件编号)和 32(总部分) - 第二个文件包含在开头:1(文件编号)和 32(总部分)...
使用 for 循环,我可以同时将所有部分发送给我的客户。 但是我的客户不能收到所有的零件,我丢失了一些零件.. 我该如何处理所要求的缺失零件?
这是我的服务器端代码:
for (int i = 0; i < nbPart + 1; i++) {
File f = null;
BufferedReader br = null;
String content = "";
byte[] sendBuffer = null;
try {
f = new File("xml/file.part" + i);
br = new BufferedReader(new FileReader(f));
StringBuilder sbuilder = new StringBuilder();
String line = br.readLine();
while (line != null) {
sbuilder.append(line);
line = br.readLine();
if (line != null) {
sbuilder.append("\n");
}
}
content = i + ";" + nbPart + "#tag#" + sbuilder.toString();
int total = new Long(f.length()).intValue();
sendBuffer = new byte[total];
sendBuffer = content.getBytes();
DatagramSocket sendSocket = new DatagramSocket();
DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, source, PORT_SEND);
sendSocket.send(sendPacket);
sendSocket.close();
Thread.sleep(timeToSend);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null)
br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
这是我的客户端代码:
while (run) {
DatagramSocket receiveSocket = null;
DatagramPacket receivePacket = null;
data = "";
byte[] receiveBuffer = new byte[9999];
Arrays.fill(receiveBuffer, (byte) 0);
try {
receiveSocket = new DatagramSocket(PORT_RECEIVE);
receivePacket = new DatagramPacket(receiveBuffer,receiveBuffer.length);
receiveSocket.receive(receivePacket);
receiveSocket.close();
data = new String(receiveBuffer, receivePacket.getOffset(), receivePacket.getLength());
String datas[] = data.split("#tag#");
String dataParts[] = datas[0].split(";");
int numPart = Integer.parseInt(dataParts[0]);
totalPart = Integer.parseInt(dataParts[1]);
if(partReceive.isEmpty()){
for(int i=0;i<totalPart+1;i++){
partReceive.add(Boolean.FALSE);
}
}
File part = new File(filePath+"/file.part"+numPart);
if(part.exists()) part.delete();
writeToFile(part, datas[1]);
partReceive.set(numPart, Boolean.TRUE);
Log.wtf("Part"+numPart, partReceive.get(numPart).toString());
} catch (Exception e) {
e.printStackTrace();
}
}
如您所见,我的第一个想法是:在客户端,我创建一个包含布尔值 (False) 的 ArrayList partReceive,当我收到一个部分时,我将 ArrayList 的索引设置为 "True" .但是在我如何处理之后?
我想到了两种可能的方法:
- 使用 TCP。它会自动确保按顺序接收所有数据包。
- 也许你故意想让你使用UDP。我不太明白你的 ArrayList
partReceive
的意义。循环将 alawys 将所有元素设置为 false,因为totalPart
在整个传输过程中保持不变。在您的示例中,它将始终为 32。我宁愿为每个数据包分配一个ID
。 ID 是唯一的编号。例如,您可以使用numPart
。收到数据包时,将其 ID 存储在列表中。整个传输完成后,检查仍然缺少哪些 id。最简单的方法是request each missing packet
.
类似的东西
ArrayList<Integer> receivedParts = new ArrayList<Integer>();
// save id of received packet
receivedParts.add(numPart);
// ...
// after transmission has finished
// Keep in mind that packets do not necessarily need to arrive in the same order like you've sent them when using UDP.
ArrayList<Integer> missingIDs = getMissingIDs(receivedParts);
for(Integer currentID : missingIDs) {
// request missing packets
requestMissingPacket(currentID);
}
检查传输是否完成有多种方式:
- 收到所有数据包后,传输。只需检查
receiveParts
列表的大小。 - 使用
timeout
。例如,如果您在 x 秒内没有收到任何数据包,则认为传输已完成。然后检查丢失了哪些数据包。