多文件自平衡云传输:资源请求、接收端

首先有几个工具类:
UnreceivedFileSectionInfo用于存储单个文件中未接收到的部分,其中有Section列表用于存储、更改所收信息。(在之前文件片段传输处理就是这个类的作用)
UnreceivedFilePool用于依据UnreceivedFileSectionInfo存储整个工程中缺少的文件。

接着整个过程:
最顶层是由用户所需的Resource建立对应的ResourceReceiver,该类依据所拥有的Resource先在本地创建接收环境(即对应的工程空目录先建立起来),接收准备做好之后就创建Requester并连接资源注册中心进行对应资源拥有者列表的索取。

在服务器发回拥有该资源的持有者列表后,就轮到接收者这边进行发送者的筛选及每个发送者任务的分配。

public boolean dealResourceSenderList(List<NodeAddress> senderList) {
			if (senderList == null || senderList.isEmpty()) {
				resourceReceiverAction.resourceNotFound();
				close();
				return false;
			}

			List<NodeAddress> senders = selectSender(senderList);
			int senderCount = senders.size();
			receiveServer = new ReceiveServer(ResourceReceiver.this, 
					senderCount, requestResourceStructor);
			try {
				receiveServer.startReceiveServer();
				receiverServerAddress = receiveServer.getReceiverServerAddress();
				
				requestResourceStructor.distributeResource(senderCount);
				List<ResourceFileSectionInfo> resourceFileSectionInfoList =
						requestResourceStructor.getResourceFileSectionList();
				
				splitSendContent(senderCount, resourceFileSectionInfoList, senderList);
			} catch (Exception e) {
				// 资源接收服务器启动异常,资源接收失败!
					resourceReceiverAction.receiveServerFailure(e);
					close();
			}
			
			return true;
		}

在筛选完发送者之后,需要接收端搭建起自身的接收服务器,等待分配到任务的发送者进行连接。
分发策略在先前解析过,这一步就省略掉。
分发后通过调用splitSendContent(这一步是RMI调用,实际调用的是ResourceSendergetSendContent)从这一步开始进入到发送者的任务,和接收端创立连接、发送资源。
这里注意的是在接收端,筛选出来的发送者数为n,那么在接收服务器会创建n个接收线程进行,即创建n个FileReceiver接收,内部用FileSectionReceiver进行接收。

public void run() {
		this.receiveServerStartup = true;
		int senderCount = 0;
		while (senderCount < this.senderCount) {
			try {
				Socket sender = this.server.accept();
				++senderCount;
				DataInputStream dis = new DataInputStream(sender.getInputStream());
				new Thread(new Runnable() {
					@Override
					public void run() {
						FileReceiver fileReceiver = new FileReceiver(
								dis, resourceStructor, randomAccessFilePool, 
								unreceivedFilePool);
						fileReceiver.receiveFile();
					}
				}).start();
			} catch (IOException e) {
				e.printStackTrace();
				break;
			}
		}
		this.resourceReceiver.close();
	}

Section接收过程:先接收一个头,记录该片段的偏移量、长度等,因为网络传输限制32k,那么这个类就会依据头片段里的长度持续接收32k,直到接收完整所需的片段再回溯到FileReceiver

public int receive() throws IOException {
		byte[] fileSectionHead = new byte[FileSectionInfo.FILE_SECTION_INFO_LEN];
		
		this.dis.read(fileSectionHead);
		this.fileSectionInfo = new FileSectionInfo(fileSectionHead);
		
		int totalLen = (int) this.fileSectionInfo.getLength();
		this.fileSection = new byte[totalLen];
		
		int offset = 0;
		int currentLen = 0;
		while (totalLen > 0) {
			currentLen = this.dis.read(this.fileSection, offset, totalLen);
			offset += currentLen;
			totalLen -= currentLen;
		}
		
		return (int) this.fileSectionInfo.getLength();
	}

FileReceiver会依据回溯来的片段借助FileSectionWriter(实际就是借助从randomAccessFilePool中取出该文件的RandomAccessFile进行寻址、写入)把接收到的片段写入文件。

public void receiveFile() {
		FileSectionReceiver fileSectionReceiver = new FileSectionReceiver(this.dis);
		int receiveSectionLen = 1;
		try {
			while (receiveSectionLen > 0) {
				receiveSectionLen = fileSectionReceiver.receive();
				if (receiveSectionLen <= 0) {
					break;
				}
				FileSectionWriter fileSectionWriter = new FileSectionWriter();
				FileSectionInfo fileSectionInfo = fileSectionReceiver.getFileSectionInfo();
				int fileNo = fileSectionInfo.getFileNo();
				fileSectionWriter.setFileSectionInfo(fileSectionInfo);
				fileSectionWriter.setFileSection(fileSectionReceiver.getFileSection());
				
				RandomAccessFile rafForWrite = this.randomAccessFilePool
						.getRandomAccessFile(fileSectionInfo.getFileNo(), "rw");
				fileSectionWriter.setRafForWrite(rafForWrite);
				fileSectionWriter.writeFileSection();
				
				UnreceivedFileSectionInfo unreceivedFileSectionInfo = this.unreceivedFilePool
						.getUnreceivedFileSection(fileNo);
				unreceivedFileSectionInfo.receiveFileSection(fileSectionInfo);
				
				if (unreceivedFileSectionInfo.isReceiveAll()) {
					this.randomAccessFilePool.close(fileNo);
					this.unreceivedFilePool.removeUnreceivedFileSection(fileNo);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

接收完片段就要在最开始的unreceivedFilePool中找到对应该文件的UnreceivedFileSectionInfo并进行未接收片段信息的更改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔幻音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值