目录
目录
模块3-资源请求
1.请求服务端向资源管理中心请求资源节点
ResourceRequestor
由于我们这篇值关注资源请求所以我们主要关注这些类:IResourceAllocation INodeSelectStrtegy
/**
*
* <ol>
* 功能:请求端向注册中心请求节点
* </ol>
* @author Quan
* @date 2020/03/07
* @version 0.0.1
*/
public class ResourceRequestor {
public static final String DEFAULT_RMI_IP = "192.168.79.1";
public static final int DEFAULT_RMI_PORT = 54188;
private String resourceCenterRmiIp;
private int resourceCenterRmiPort;
private ClientProxy clientProxy;
/**
* 当有很多可提供资源发送的节点时,需要将一份资源切片分别交与提供者
* 这就是资源分配的接口
*/
private IResourceAllocation resourceAllocation;
/**
* 供外部得view层实现的接口
*/
private IRecieveViewAction recieveViewAction;
/**
* 节点选择策略,用来在客户端的节点选择
*/
private INodeSelectStrtegy nodeSelectStrtegy;
private List<Node> reallySendNodeList;
private ReceiverServer receiverServer;
private static int port = ReceiveServerPortPool.next();
public ResourceRequestor() {
resourceCenterRmiIp = DEFAULT_RMI_IP;
resourceCenterRmiPort = DEFAULT_RMI_PORT;
nodeSelectStrtegy = new NodeSelectStrtegy();
reallySendNodeList = new ArrayList<Node>();
this.resourceAllocation = new ResourceAllocation();
receiverServer = new ReceiverServer();
receiverServer.setThreadPool(new MThreadPool().newInstance(false));
}
public IResourceAllocation getResourceAllocation() {
return resourceAllocation;
}
public void setResourceAllocation(IResourceAllocation resourceAllocation) {
this.resourceAllocation = resourceAllocation;
}
public String getResourceCenterRmiIp() {
return resourceCenterRmiIp;
}
public void setResourceCenterRmiIp(String resourceCenterRmiIp) {
this.resourceCenterRmiIp = resourceCenterRmiIp;
}
public int getResourceCenterRmiPort() {
return resourceCenterRmiPort;
}
public void setResourceCenterRmiPort(int resourceCenterRmiPort) {
this.resourceCenterRmiPort = resourceCenterRmiPort;
}
public IRecieveViewAction getRecieveViewAction() {
return recieveViewAction;
}
public void setRecieveViewAction(IRecieveViewAction recieveViewAction) {
this.recieveViewAction = recieveViewAction;
}
private ClientProxy prepareClientProxy() {
if (clientProxy == null) {
synchronized (ResourceRequestor.class) {
if (clientProxy == null) {
clientProxy = new ClientProxy();
clientProxy.setRmiClient(new RMIClient(resourceCenterRmiPort, resourceCenterRmiIp));
}
}
}
return clientProxy;
}
/**
* 请求资源:
* 1.向中心请求到提供者列表
* 2.将的到的列表以策略选择节点
* 3.分配资源
* 4.联系节点并开启接受端
* @param rbi
* @param selfPath
*/
public void requestResource(ResourceBaseInfo rbi, String selfPath) {
if (recieveViewAction == null) {
System.out.println("请先设置view");
return;
}
List<Node> nodeList = getPortFromCenter(rbi);
List<Node> resultNode = nodeSelectStrtegy.selectNodeList(resultNode);
if (resultNode == null) {
recieveViewAction.receiveFail("资源中心未开启 || 资源中心没有该资源 -- 请稍后再试");
return;
}
int senderCount = resultNode.size();
receiverServer.setRbi(new ResourceBaseInfo(rbi).setAbsoluteRoot(selfPath));
receiverServer.setPort(port);
receiverServer.setDelayTime(5000);
receiverServer.setAction(recieveViewAction);
receiverServer.startUp();
List<List<FileSectionInfo>> fsiListList = resourceAllocation.allocationSectionInfo(rbi.getFsiList(), senderCount);
Node me = new Node(ReceiverServer.ip, port);
int reallySenderCount = 0;
try {
reallySenderCount = distributeSendSection(me, resultNode, rbi, fsiListList);
} catch (Exception e) {
}
if (reallySenderCount > 0 && reallySenderCount <= senderCount) {
receiverServer.setReallySendNodeList(reallySendNodeList);
} else {
recieveViewAction.hasNoSender();
ReceiverServer.close();
return;
}
}
public void requestResourceAgain(List<Node> nodeList, ResourceBaseInfo rbi, String selfPath) throws Exception {
if (nodeList.isEmpty()) {
recieveViewAction.hasNoSender();
throw new WrongAgainTransferException("断点无Port可再用,请重新下载");
}
int senderCount = nodeList.size();
List<List<FileSectionInfo>> fsiListList = resourceAllocation.allocationSectionInfo(rbi.getFsiList(), senderCount);
Node me = new Node(ReceiverServer.ip, port);
int reallySenderCount = distributeSendSection(me, nodeList, rbi, fsiListList);
if (reallySenderCount > 0 && reallySenderCount <= senderCount) {
receiverServer.setReallySendNodeList(reallySendNodeList);
ReceiverServer.setTimerFlag(false);
} else {
recieveViewAction.hasNoSender();
ReceiverServer.close();
return;
}
}
private int distributeSendSection(Node receiver, List<Node> senderList, ResourceBaseInfo orgRbi, List<List<FileSectionInfo>> fsiListList) throws Exception {
int senderCount = senderList.size();
int reallySenderCount = senderCount;
for (Node node : senderList) {
reallySendNodeList.add(node);
}
ClientProxy rmiClientProxy = new ClientProxy();
RMIClient rmiClient = new RMIClient();
for (int i = 0; i < senderCount; i++) {
INetNode senderNode = senderList.get(i);
rmiClient.setRmiIp(senderNode.getIp());
rmiClient.setRmiPort(senderNode.getPort());
rmiClientProxy.setRmiClient(rmiClient);
ResourceBaseInfo targetResource = new ResourceBaseInfo(orgRbi);
targetResource.setFsiList(fsiListList.get(i));
ISendSection resourceSender = rmiClientProxy.getProxy(ISendSection.class, false);
try {
resourceSender.sendSectionInfo(receiver, targetResource);
for (List<FileSectionInfo> list : fsiListList) {
System.out.println(list);
}
} catch (Exception e) {
rmiClient.setRmiIp(resourceCenterRmiIp);
rmiClient.setRmiPort(resourceCenterRmiPort);
clientProxy.setRmiClient(rmiClient);
ICenterAction action = clientProxy.getProxy(ICenterAction.class, false);
boolean ok = action.logOutNode(new Node(senderNode.getIp(), senderNode.getPort()));
if (ok == false) {
throw new Exception("注册中心注销节点失败,强制退出,否则出现假死循环");
} else {
}
reallySendNodeList.remove(senderNode);
reallySenderCount--;
}
}
return reallySenderCount;
}
public List<Node> getPortFromCenter(ResourceBaseInfo rbi) {
ClientProxy clientProxy = prepareClientProxy();
ICenterAction action = clientProxy.getProxy(ICenterAction.class, false);
try {
List<FileSectionInfo> fsiList = rbi.getFsiList();
List<ResourceStructInfo> rsiList = rbi.getRsiList();
rbi.setFsiList(null);
rbi.setRsiList(null);
List<Node> nodeList = action.requestResource(rbi);
rbi.setFsiList(fsiList);
rbi.setRsiList(rsiList);
if (nodeList.size() == 0) {
return null;
}
return nodeList;
} catch (Exception e) {
return null;
}
}
}
INodeSelectStrtegy
/**
*
* <ol>
* 功能:节点选择策略接口
* </ol>
* @author Quan
* @date 2020/03/07
* @version 0.0.1
*/
public interface INodeSelectStrtegy {
int DEFAULT_MAX_SEND_COUNT = 5;
int MIN_SEND_COUNT = 1;
List<Node> selectNodeList(List<Node> nodeList);
void setMaxSenderCount(int maxSendCount);
}
NodeSelectStrategy
/**
*
* <ol>
* 功能:节点选择策略接口实现
* <li>使用桶排序的方法以发送节点的次数来进行自平衡</li>
* </ol>
* @author Quan
* @date 2020/03/07
* @version 0.0.1
*/
public class NodeSelectStrtegy implements INodeSelectStrtegy {
private int maxSenderCount;
public NodeSelectStrtegy() {
maxSenderCount = DEFAULT_MAX_SEND_COUNT;
}
@Override
public void setMaxSenderCount(int maxSenderCount) {
this.maxSenderCount = maxSenderCount > MIN_SEND_COUNT
? maxSenderCount : MIN_SEND_COUNT;
}
@Override
public List<Node> selectNodeList(List<Node> orgSendList) {
List<Node> nodeList = orgSendList;
try {
int senderCount = nodeList.size();
if (senderCount <= 1) {
return nodeList;
}
senderCount = nodeList.size();
if (senderCount > maxSenderCount) {
nodeList = selectMinSendNode(nodeList);
}
return nodeList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private List<Node> selectMinSendNode(List<Node> nodeList) {
List<Node> resultNodeList = new ArrayList<Node>();
int index = 0;
Node maxNode = nodeList.get(index);
for (index = 1; index < nodeList.size(); index++) {
Node node = nodeList.get(index);
if (maxNode.getSendTime() < node.getSendTime()) {
maxNode = node;
}
}
int[] sendCount = new int[maxNode.getSendTime()];
for (index = 0; index < nodeList.size(); index++) {
int nodeSendTime = nodeList.get(0).getSendTime();
sendCount[nodeSendTime]++;
}
int maxSenderCount = this.maxSenderCount;
for (index = 0; index < maxSenderCount; index++) {
if (maxSenderCount >= 0) {
maxSenderCount -= sendCount[index];
if (maxSenderCount < 0) {
sendCount[index] += maxSenderCount;
}
} else {
sendCount[index] = 0;
}
}
for (index = 0; index < nodeList.size(); index++) {
Node node = nodeList.get(index);
int count = node.getSendTime();
if (sendCount[count] >= 0) {
resultNodeList.add(node);
sendCount[count]--;
}
}
return resultNodeList;
}
}
IResourceAllocation
/**
*
* <ol>
* 功能:资源分配策略
* </ol>
* @author Quan
* @date 2020/03/07
* @version 0.0.1
*/
public interface IResourceAllocation {
int DEFAULT_MAX_SECTION_LENGTH = 1 << 22;
int MIN_SECTION_LENGTH = 1 << 16;
void setMaxSectionLength(int maxSectionLength);
List<List<FileSectionInfo>> allocationSectionInfo(List<FileSectionInfo> fsiList, int senderCount);
}
ResourceAllocation
/**
*
* <ol>
* 功能:资源分配实现
* </ol>
* @author Quan
* @date 2020/03/07
* @version 0.0.1
*/
public class ResourceAllocation implements IResourceAllocation {
private int maxSectionLength;
public ResourceAllocation() {
maxSectionLength = DEFAULT_MAX_SECTION_LENGTH;
}
@Override
public void setMaxSectionLength(int maxSectionLength) {
if (maxSectionLength > MIN_SECTION_LENGTH) {
this.maxSectionLength = maxSectionLength;
}
}
@Override
public List<List<FileSectionInfo>> allocationSectionInfo(List<FileSectionInfo> fsiList, int senderCount) {
if (senderCount < 0) {
return null;
}
List<List<FileSectionInfo>> sectionListList = new ArrayList<>();
for (int index = 0; index < senderCount; index++) {
List<FileSectionInfo> sectionList = new ArrayList<FileSectionInfo>();
sectionListList.add(sectionList);
}
int index = 0;
for (FileSectionInfo fsi : fsiList) {
int fSize = fsi.getSize();
if (fSize < maxSectionLength) {
List<FileSectionInfo> indexList = sectionListList.get(index);
indexList.add(fsi);
index = (index + 1) % senderCount;
continue;
}
long offset = 0L;
int restLen = fSize;
int len;
while (restLen > 0) {
len = restLen > maxSectionLength ? maxSectionLength : restLen;
List<FileSectionInfo> indexList = sectionListList.get(index);
indexList.add(new FileSectionInfo(fsi.getFileHandle(), offset + fsi.getOffset(), len));
offset += len;
restLen -= len;
index = (index + 1) % senderCount;
}
}
return sectionListList;
}
}
2.请求服务端向资源提供端请求资源片段
我将要发送的资源请求片段和资源节点以RMI接受方式放置在资源提供端实现此时接口为:ISendSection
ISendSection
public interface ISendSection {
void sendSectionInfo(Node receiverNode, ResourceBaseInfo rbi);
}
最后
资源的放置
若是资源成功接受我们需要将它放置在自己的资源池中
ResourcePool
/**
* 每个资源端应该有的
* <ol>
* 功能:存放资源框架
* </ol>
* @author Quan
* @date 2020/02/08
* @version 0.0.1
*/
public class ResourcePool {
private static final Map<String, ResourceBaseInfo> resourcePool = new HashMap<String, ResourceBaseInfo>();
public ResourcePool() {
}
/**
* 接受APP服务器发过来的资源框架信息<br>
* <li>
* 情况一:
* 若发送的资源框架信息没有存在,则加入
* </li>
* <li>
* 情况二:
* 若发送的资源框架信息存在,则比较版本
* <ol>
* 一:若版本一致,不处理
* </ol><ol>
* 二:若不一致则按照第一种情况处理。
* </ol>
* </li>
* @param rbi
* @return
*/
public boolean addResource(ResourceBaseInfo rbi) {
String name = rbi.getName();
ResourceBaseInfo orgRbi = resourcePool.get(name);
if (orgRbi == null || rbi.getVersion() != orgRbi.getVersion()) {
resourcePool.put(name, rbi);
return true;
}
return false;
}
public boolean removeResource(ResourceBaseInfo rbi) {
String name = rbi.getName();
ResourceBaseInfo orgRbi = resourcePool.get(name);
if (orgRbi != null && rbi.getVersion() == orgRbi.getVersion()) {
resourcePool.remove(name, orgRbi);
return true;
}
return false;
}
public static ResourceBaseInfo getResourceBaseInfo(String name) {
return resourcePool.get(name);
}
public boolean isEmpty() {
return resourcePool.isEmpty();
}
}