使用 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" .但是在我如何处理之后?

我想到了两种可能的方法:

  1. 使用 TCP。它会自动确保按顺序接收所有数据包。
  2. 也许你故意想让你使用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 秒内没有收到任何数据包,则认为传输已完成。然后检查丢失了哪些数据包。