多文件自平衡云传输框架(4)-- 资源请求(向资源管理中心和拥有资源的节点)

目录

模块3-资源请求

1.请求服务端向资源管理中心请求资源节点

ResourceRequestor

INodeSelectStrtegy

NodeSelectStrategy

IResourceAllocation

ResourceAllocation

2.请求服务端向资源提供端请求资源片段

ISendSection

最后

资源的放置

ResourcePool


目录

模块3-资源请求

1.请求服务端向资源管理中心请求资源节点

ResourceRequestor

INodeSelectStrtegy

NodeSelectStrategy

IResourceAllocation

ResourceAllocation

2.请求服务端向资源提供端请求资源片段

ISendSection


模块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();
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值