多文件自平衡云模式文件传输系统(下)

多文件自平衡云模式文件传输系统(下)

下面我们开始处理文件的发送和接受。

文件的发送与接收

关于文件的发送和接收,我们将它定义在一个接口中。

// 
public interface ISendReceive {
 void send(DataOutputStream dos, byte[] content) throws Exception;
 byte[] receive(DataInputStream dis, int len) throws Exception;
}

它的实现类如下:

// 
public class NetSendReceive implements ISendReceive {
 public static final int DEFAULT_SECTION_LEN = 1 << 15;
 private int bufferSize;
 
 public NetSendReceive() {
  this.bufferSize = DEFAULT_SECTION_LEN;
 }
  
 public ISendReceive setBufferSize(int bufferSize) {
  this.bufferSize = bufferSize;
  return this;
 }
 
 @Override
 public void send(DataOutputStream dos, byte[] content) throws Exception {
  int len = content.length;
  int offset = 0;
  int curLen;
  
  while (len > 0) {
   curLen = len > this.bufferSize ? this.bufferSize : len;
   dos.write(content, offset, curLen);
   offset += curLen;
   len -= curLen;
  }
 }
 
 @Override
 public byte[] receive(DataInputStream dis, int len) throws Exception {
  byte[] buffer = new byte[len];
  
  int curLen;
  int factLen;
  int offset = 0;
  while (len > 0) {
   curLen = len > this.bufferSize ? this.bufferSize : len;
   factLen = dis.read(buffer, offset, curLen);
   // System.out.println("本次接收字节数:" + factLen);
   len -= factLen;
   offset += factLen;
  }
  
  return buffer;
 }

}

在用户定义如何发送、接受文件片段后,我们需要思考的是如何按上一篇约定的格式发送、接受文件片段。

//
public class FileSectionSendReceive {
 private ISendReceive sendReceive;
   
 public FileSectionSendReceive() {
  this.sendReceive = new NetSendReceive();
 }
 
 public void setSendReceive(ISendReceive sendReceive) {
  this.sendReceive = sendReceive;
 }


 public void sendLastSection(DataOutputStream dos) throws Exception {
  FileSectionInfo sectionInfo = new FileSectionInfo(0, 0, 0);
  sectionInfo.setContent(new byte[0]);
  sendReceive.send(dos, sectionInfo.toBytes());
 }
  
 public void sendSection(DataOutputStream dos, FileSectionInfo sectionInfo) throws Exception {
  sendReceive.send(dos, sectionInfo.toBytes());
  if (sectionInfo.getLen() <= 0) {
   return;
  }
  sendReceive.send(dos, sectionInfo.getContent());
 }
  
 public FileSectionInfo receiveSection(DataInputStream dis) throws Exception {
  byte[] head = sendReceive.receive(dis, 16);
  FileSectionInfo sectionInfo = new FileSectionInfo(head);
  int sectionLen = sectionInfo.getLen();
  if (sectionLen > 0) {
   sectionInfo.setContent(sendReceive.receive(dis, sectionLen));
  }
  
  return sectionInfo;
 }

}

由于接收端可能接收多个文件,而这些文件又是由多个发送端分片段发送
的;这意味着,接收端所接收的片段,对应的文件未必是“聚集”的;
也就是说,对于接收端,可能会出现在多个文件来回切换“接收”的情
况。对于文件的接收过程,需要依赖于RandomAccessFile类对象;每
接收一个片段,在完成这个片段内容向文件写前,必须先建立RAF对
象;当这个片段接收完毕后,下一个片段极有可能是另一个文件。这
就会产生,接收端需要不停的对同一个文件,产生RAF对象的可能。
RAF对象的初始化和关闭过程也是需要消耗系统资源的。在此我们可以考虑能否建立一个RAF迟,当一个文件开始读写时,除非接受完毕,否则不轻易关闭,但是在此处需要考虑到多个线程同时写一个文件时的安全问题。

// 
public class FileReadWrite {
 private int fileNo;
 private String filePath;
 private RandomAccessFile raf;
  
 public FileReadWrite(int fileNo, String filePath) {
  this.fileNo = fileNo;
  this.filePath = filePath;
 }
  
 public int getFileNo() {
  return fileNo;
 }
  
 public FileSectionInfo readSection(FileSectionInfo section) throws IOException {
  if (raf == null) {
   raf = new RandomAccessFile(filePath, "r");
  }
  raf.seek(section.getOffset());
  
  int len = section.getLen();
  byte[] buffer = new byte[len];
  raf.read(buffer);
  section.setContent(buffer);
  
  return section;
 }
  
 public boolean writeSection(FileSectionInfo section) {
  if (this.raf == null) {
   synchronized (filePath) {
    if (this.raf == null) {
     try {
      this.raf = new RandomAccessFile(filePath, "rw");
     } catch (FileNotFoundException e) {
      e.printStackTrace();
      return false;
     }
    }
   }
  }
  
  try {
   synchronized (filePath) {
    raf.seek(section.getOffset());
    raf.write(section.getContent());
   }
  } catch (IOException e) {
   return false;
  }
  
  return true;
 }
  
 public void close() {
  try {
   this.raf.close();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 
}

 

我们建立一个ResourceFilePool类(池子)将所有文件对应的FileReadWrite放到池子中,除非文件收发结束,不轻易销毁RandomAccessFile对象,降低系统的资源消耗。

// 
public class ResourceFilePool {
 private Map<Integer, FileReadWrite> fileAcceptPool;
  
 public ResourceFilePool() {
  this.fileAcceptPool = new HashMap<Integer, FileReadWrite>();
 }
 
 public void addFileInfo(int fileNo, String filePath) {
  FileReadWrite readWrite = new FileReadWrite(fileNo, filePath);
  this.fileAcceptPool.put(fileNo, readWrite);
 }
  
 public FileReadWrite getFileAccpet(int fileNo) {
  return this.fileAcceptPool.get(fileNo);
 }
  
 public void addFileList(SourceFileList sourList) {
  List<FileInfo> fileList = sourList.getFileList();
  for(FileInfo file : fileList) {
   addFileInfo(file.getFileNo(), sourList.getAbsoluteRoot() + file.getFilePath());;
  }
 }
 
}

== 文件的发送 == :

// 
public class FileSender implements Runnable{
 private String receiveIp;
 private int receivePort;
 private ResourceFilePool  rscPool;
 private List<FileSectionInfo> sectionList;
 private FileSectionSendReceive FileSectionSend;
  
 public FileSender(String receiveIp, int receivePort, ResourceFilePool rscPool,
   List<FileSectionInfo> sectionList) {
  this.receiveIp = receiveIp;
  this.receivePort = receivePort;
  this.rscPool = rscPool;
  this.sectionList = sectionList;
  this.FileSectionSend = new FileSectionSendReceive();
 }
  
 public void startSend() {
  new Thread(this, "文件发送").start() ;
 }
  
 @Override
 public void run() {
  Socket socket = null;
  DataOutputStream dos = null;
    
  try {
   socket = new Socket(receiveIp, receivePort);
   dos = new DataOutputStream(socket.getOutputStream());
      
   for(FileSectionInfo section : sectionList) {
    FileReadWrite readWrite = rscPool.getFileAccpet(section.getFileNo());
    section = readWrite.readSection(section);
    FileSectionSend.sendSection(dos, section);
   }
   
    FileSectionSend.sendLastSection(dos);
    ResourceSender.incSendCount(); 
  } catch (UnknownHostException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } catch (Exception e) {
   e.printStackTrace();
  }finally {
   ResourceSender.decSendCount();
   close(socket, dos);
  }
 }
 
 private void close(Socket socket, DataOutputStream dos) {
  try {
   if(dos != null) {
     dos.close();
   }
  } catch (IOException e) {
   e.printStackTrace();
  }
  
  if(socket != null && !socket.isClosed()) {
   try {
    socket.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

}

下面这个类ResourceSender是对FileSender类的进一步封装与完善,增加了文件片段发送的计数功能等。

// 
public class ResourceSender implements IResourceSender{
 private SourceHolderNode holder;
 private static final SendCounter sendCounter = new SendCounter();
  
 public ResourceSender() {
  this.holder = SourceHolderNode.newInstance();
 }
  
 public static void incSendCount() {
  sendCounter.incSendAccount();
 }
  
 public static void decSendCount() {
  sendCounter.decSendCount();
 }
  
 @Override
 public void sendResource(String receiveIp, int receivePort, ResourceInfo baseInfo,
   List<FileSectionInfo> sectionList) {
  sendCounter.incSendCount();
  SourceFileList fileList = holder.getSourceFileList(baseInfo);
  ResourceFilePool rscFilePool = new ResourceFilePool();
  rscFilePool.addFileList(fileList);
  
  FileSender fileSender = new FileSender(receiveIp, receivePort, rscFilePool, sectionList);
  fileSender.startSend();
 }
 
 @Override
 public SendCounter getSendCounter() {
  return sendCounter;
 }
 
}

== 文件的接受 ==:

下面展示一些 接收端代码片

接收端服务器:

// 
public class ReceiveServer implements Runnable{
 private static final int DEFAULT_RECEIVE_PORT = 54191;
  
 private ServerSocket server;
 private String ip;
 private int port;
 private int sendCount;
 private volatile boolean goon;
 private ThreadPoolExecutor executor;
  
 private ResourceFilePool receiveFilePool;
  
 public ReceiveServer() {
  try {
   this.ip = InetAddress.getLocalHost().getHostAddress();
   this.executor = new ThreadPoolExecutor(5, 20, 500, 
     TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
   this.receiveFilePool = new ResourceFilePool();
   this.port = DEFAULT_RECEIVE_PORT;
   this.goon = false;
   this.sendCount = 0;
  } catch (UnknownHostException e) {
   e.printStackTrace();
  }
 }
 
 public void setPort(int port) {
  this.port = port;
 }
 
 public void setSendCount(int sendCount) {
  this.sendCount = sendCount;
 }
 
 public String getIp() {
  return ip;
 }
 
 public void setIp(String ip) {
  this.ip = ip;
 }
 
 public void setReceiveFilePool(SourceFileList sourceFileList) {
  String absolutePath = sourceFileList.getAbsoluteRoot();
  List<FileInfo> fileList = sourceFileList.getFileList();
  
  for(FileInfo file : fileList) {
   this.receiveFilePool.addFileInfo(file.getFileNo(),
     absolutePath + file.getFilePath());
  }
 }
 
 public void startup() {
  if(this.goon) {
   return;
  }
  try {
   this.server = new ServerSocket(port);
   this.goon = true;
   new Thread(this, "接收服务器").start();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
  
 private void shutdown() {
  if(this.server != null && !this.server.isClosed()) {
   try {
    this.server.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }
  
 @Override
 public void run() {
  if(this.sendCount <= 0) {
   return;
  }
  for(int count = 0; count < this.sendCount; count++) {
   try {
    Socket sender = this.server.accept();
    Receiver receiver = new Receiver(sender);
    this.executor.execute(receiver);
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
  shutdown();
 }
  
 public class Receiver implements Runnable {
  private Socket socket;
  private DataInputStream dis;
  private FileSectionSendReceive sectionReceive;
  
  public Receiver(Socket socket) throws IOException {
   this.socket = socket;
   this.sectionReceive = new FileSectionSendReceive();
   this.dis = new DataInputStream(this.socket.getInputStream());
  }
    
  @Override
  public void run() {
   try {
    FileSectionInfo section = sectionReceive.receiveSection(dis);
    while(section.getLen() > 0) {
     FileReadWrite file = receiveFilePool.getFileAccpet(section.getFileNo());
     file.writeSection(section);
     
     section = sectionReceive.receiveSection(this.dis);
    }
   } catch (Exception e) {
    e.printStackTrace();
   }
   }
   }
}
 

接收端:

// 
public class ResourceReceiver {
 private ResourceInfo baseInfo;
 private SourceFileList fileList;
 private ResourceRequester request;
 private FileDistribution fileDistribution;
 private ISenderSelectedStrategy senderSelectedStrategy;
  
 private RMIClient receiveClient;
 private IResourceSender resourceSender;
  
 private ReceiveServer receiveServer;
  
 public ResourceReceiver() {
  this.request = new ResourceRequester();
  this.fileDistribution = new FileDistribution();
  this.senderSelectedStrategy = new DefaultSenderSelector();
  this.receiveServer = new ReceiveServer();
 }
 
 public void setMaxFileSectionSize(int maxSectionSize) {
  this.fileDistribution.setMaxSectionSize(maxSectionSize);
 }
  
 public void setDistributionStrategy(IDistributionStrategy strategy) {
  this.fileDistribution.setDistributionStrategy(strategy);
 }
  
 public void setSenderSelectedStrategy(ISenderSelectedStrategy strategy) {
  this.senderSelectedStrategy = strategy;
 }
  
 public void setResourceRegistryCenterIp(String ip) {
  this.request.setRmiServerIp(ip);
 }
  
 public void setResourceRegistryCenterPort(int port) {
  this.request.setRmiServerPort(port);
 }
  
 public void setBaseInfo(ResourceInfo baseInfo) {
  this.baseInfo = baseInfo;
 }
  
 public void setFileList(SourceFileList fileList) {
  this.fileList = fileList;
 }
  
 public void setAbsoluteRoot(String absoluteRoot) {
  this.fileList.setAbsoluteRoot(absoluteRoot);
 }
  
 public void setReceiveServerIp(String ip) {
  this.receiveServer.setIp(ip);
 }
  
 public void setReceiveServerPort(int port) {
  this.receiveServer.setPort(port);
 }
 
  public void getResourceFiles() throws ResourceNotExistException {
  //TODO 这里要启动接受端的接收进度 监控条
  List<DefaultNetNode> senderList = request.getAddressList(baseInfo);
  if(senderList == null || senderList.isEmpty()) {
   throw new ResourceNotExistException("资源[" +  baseInfo + "]不存在!");
  }
  
  //senderList = this.senderSelectedStrategy.selectesSender(senderList);
  
  int sendCount = senderList.size();
  List<List<FileSectionInfo>> fileSectionListList = 
    this.fileDistribution.distribution(this.fileList, sendCount);
  
  this.receiveServer.setReceiveFilePool(fileList);
  this.receiveServer.setSendCount(sendCount);
  //this.receiveServer.startup();
  
  int index = 1;
  for(List<FileSectionInfo> sectionList : fileSectionListList) {
   System.out.println("第" + index + "个发送端要发送的片段列表:");
   int i = 1;
   for(FileSectionInfo section : sectionList) {
    System.out.println("\t" + index + "-" + "(" + i + ")");
    i++;
   }
   ++index;
   //TODO 想发送端传递:
   //1、接收端服务器ip和port;
   //2、资源详细列表,即FileList;
   //3、文件片段列表 即 List<FileSectionInfo>;
   //4、启动发送端开始发送!(这里通过创建新线程实现启动并完成发送);
  }
 }
}

== 注册中心 ==

下面展示一些 内联代码片

// An highlighted block
public class ResourceCenterServer implements IResourceListener {
 public static final int RSCPort = 54187;
 private ResourceRegistryCenter center;
  
 public ResourceCenterServer() {
  this.center = new ResourceRegistryCenter(RSCPort);
  this.center.addListener(this);
 }
  
 public void startup() {
  this.center.startup();
 }
  
 @Override
 public void dealMessage(String message) {
  System.out.println(message);
 }
  
 @Override
 public void dealMessage(String message) {
  System.out.println(message);
 }

上面就是关于多文件云传输的代码部分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值