资源发送者负责发送接收端指定的资源片段。
1.资源发送端应该采取什么模式发送资源?
两种发送模式:
- 单发送端对单接收端
- 多发送端对单接收端
模式2效率明显较高。
一对多模式,采用C/S网络通信。
客户端:发送端。
服务器:接收端。
2.资源发送线程
- 资源发送端发送资源的前提:
- 本地资源列表。
- 发送端ip和port。
- 发送端请求的资源片段信息。
public Sender(Socket socket, ResourceInfo resourceInfo,
List<SectionHander> sectionList,IActionSendAfter sendAfter) {
try {
this.socket = socket;
this.resourceInfo = resourceInfo;
this.sendAfter = sendAfter;
this.sectionList = sectionList;
this.dos = new DataOutputStream(socket.getOutputStream());
this.sectionTransfer = new SectionTransfer();
randomAccessFilePool = new RandomAccessFilePool(resourceInfo);
//根据文件id排序
sectionList.sort((one, two) -> Long.compare(one.getFileId(),two.getFileId()));
} catch (IOException e) {
e.printStackTrace();
}
}
- 接收的Run方法
这里根据文件片段,发送文件资源,但何时关闭文件文件资源?
只要将文件发送完毕就可以关闭?但文件片段列表,是混乱的。所以需要将片段列表重排序根据文件id。
发送端检测到文件id变化时,就需要将上一个文件资源关闭。
/**
* 根据文件片段信息 读取文件,并发送
* 这里存在一个问题:
* 我想打开 关闭一次文件,如何实现?
* 文件片段集合,文件排序是混乱不清的
* 需要统一文件片段相邻,本质上为分组,根据文件id排序
*/
@Override
public void run() {
long lastFileId = 0;
long fileId = 0;
for (SectionHander sectionHander : sectionList) {
try {
fileId = sectionHander.getFileId();
RandomAccessFile file = randomAccessFilePool.getRandomAccessFile(fileId, "r");
byte[] buffer = FileAccessor.readSection(file, sectionHander.getOffset(),
(int) sectionHander.getLen());
sectionTransfer.sendSection(dos, sectionHander, buffer);
if (lastFileId != fileId) {
randomAccessFilePool.closeRaf(lastFileId);
lastFileId = fileId;
}
} catch (IOException e) {
e.printStackTrace();
}
}
randomAccessFilePool.closeRaf(fileId);
try {
sectionTransfer.sendEnd(dos);
} catch (IOException e) {
e.printStackTrace();
}
senAfter.afterSend();
}
完成发送后,这里给了一个扩展接口,可以补充做一些事。
package man.kuke.core;
/**
* @author: kuke
* @date: 2020/12/5 - 12:11
* @description:
*/
public interface IActionSendAfter {
void afterSend();
}
3.发送端
负责与接收端连接。
package man.kuke.core;
import java.io.IOException;
import java.net.Socket;
import java.util.Comparator;
import java.util.List;
/**
* @author: kuke
* @date: 2020/12/5 - 12:01
* @description:
*/
public class SenderClient {
public static String DEFAULT_IP = "127.0.0.1";
private String receiveIp;
private int port;
private Socket socket;
//资源信息
private ResourceInfo resourceInfo;
//接收端资源请求片段
private List<SectionHander> handerList;
public SenderClient(String receiveIp, int port,ResourceInfo resourceInfo,
List<SectionHander> handerList) {
this.receiveIp = receiveIp;
this.port = port;
this.resourceInfo = resourceInfo;
this.handerList = handerList;
}
public String getReceiveIp() {
return receiveIp;
}
public void setReceiveIp(String receiveIp) {
this.receiveIp = receiveIp;
}
public void send() throws IOException {
socket = new Socket(receiveIp,port);
Sender sender = new Sender(socket, resourceInfo, handerList,new IActionSendAfter(){
@Override
public void afterSend() {
//TODO 发送后
}
});
sender.start();
}
}
要与接收端建立C/S通信前提是获取接收端ip、port、请求资源列表。
而这些接收端有该如何获取?