资源请求者功能
1.资源请求者在资源接收资源前应该得到资源信息
2.向资源注册中心请求资源拥有者节点。
3.依据资源拥有者节点的健康情况来选择真正的资源发送者(负载均衡)
4.对接收的文件进行写入具体的文件,在接收一段文件后在未接收池中进行一次截取这次接收文件的片段(体现实收真正的接收完毕)。
5.在真正接收完毕后向注册中心注册接收资源。
资源请求者工作流程
首先因为注册中心肯定是启动了RMI服务器的,就直接请求拥有者地址列表,在申请到列表后选择一个最健康的资源拥有者。因为每个资源拥有者都是在注册资源后开启了,RMI服务器等待资源请求者向其请求文件片段的。这时选择一个最健康的资源拥有者让其发送资源信息。在接收完资源信息后,根据设置的资源发送者个数以及这时资源发送者个数来设置真实发送者是哪些。选择完毕后就开始文件分片,分片完毕后利用RMI来传输要求资源拥有者发送的资源,完成后开启接收服务器。这时就完成了资源请求者的一切,等待发送者连接并发送文件。
资源请求者实现细节
1.关于UnreceivePool以及UnreceiveSection的编写。
这个类还有些遍历操作就不一一展示了。
UnreceivePool通过每一个文件的信息来集合为一个map,key是文件id,值是该文件未接收的section。只要接收了某一文件的文件片段,那么就会在unceivePool中找到该文件然后截取片段。
接下来介绍其他类及其作用
ResourceReceiver是在资源请求者最上层,通过app提供文件id,从而开始资源的请求。开始后首先会初始化一个ReceiverServer开始侦听资源拥有者的连接请求。每连接一个资源拥有者,就初始化一个Receiver,每一个Receiver进行文件的读写和UnreceivePool的文件片段截取。两个接口一个是根据健康值选择参与发送的资源拥有者,一个是写文件的操作。还有一个就是选择拥有者的策略。
ResourceReceiver会通过RMI进行资源拥有者地址列表的请求(IResourceRegistryCenterAction),这里注册中心的ip和port通过配置文件给出。得到了地址列表后遍历这个地址列表,通过每一个ip和port设置RMIClient,就向每一个RMI服务器发送需要发送的文件信息(这个信息是通过ResourceSpliter和senderCount来分割ResourceInfo构成的,当然这个senderCount是通过选择策略选择的)。
这里一定是要用线程来做,不然就会等待每一个资源拥有者发送完后下一个才开始。其次就是在发送消息前一定要开启ReceiverServer。
这里是通过senderCount和resourceInfo来初始化receiverServer,之所以要senderCount是因为要控制何时停止侦听,不然就算所有资源拥有者都连接了还会一直在侦听,然后子所以要newUnreceivePool()这个方法是因为,resourceinfo中是文件id对应文件信息,而unceivePool是文件id对应UnreceiveSection,所以需要转换。
连接一个开启一个receiver,receiver中一个内部类实现了IsectionProcessor这个接口
构造方法以及开启线程如下:
在以前写的SectionTransfer类中进行接收,因为在receiver中内部类实现了接口,在这里设置了,所以进行接收后会进行写操作。
这里就完成了接收者的编写。
以上是接收具体文件信息,但是还没有完成resourceInfo的接收,所以这里补写。因为要考虑文件过于庞大可能会导致字符串过于长,一次发送是不可能发送完的,超过65535会报异常
总结
资源接收者会在资源接收前向资源注册中心申请资源拥有者地址列表(RMI完成)。通过得到现在的资源拥有者地址列表选择一个发送端(负载均衡)来发送resouceinfo的基本信息,得到后,创建文件的目录。然后执行receiveResourceInfo,开始真正的接收。开始接收过程是先根据现有资源拥有者数量和选择策略,确认真正的发送端。开启接收服务器,通过RMI向每个发送端发送请求资源的请求。服务端侦听到连接,连接后初始化一个receiver开始真正的接收和写文件。
值得注意:
这里的写文件就是多线程的,因为有可能在同一时间不同的线程会去写同一个文件的不同位置,因为我们的RandomAccessFile是在map里获得同一个,以至于不加锁的话会写错,所以我在写FileAccessor中写的writeSection会写synchronized。