资源发送端的功能
1.注册资源
2.注销资源
3.资源发送
对于注册资源和注销资源来说这两大功能一直都是资源提供者所实现的,资源发送端应用了资源提供者的功能,并且自身又进行了资源发送功能的扩展。
Provider
/*
*资源提供者:专注于资源的注册和注销的功能
*/
public class Provider {
private rmiCilent rc;
private static int PORT = 54200;
private static String IP = "192.168.230.1";
private CilentProxy cp;
private int RegisterPort = PORT;
private String RegisterIp = IP;
private static NetNode self = new NetNode();
static {
self.setIp(getSelfIp());
self.setPort(54188);
}
public Provider() {
this.RegisterIp = IP;
this.RegisterPort = PORT;
this.cp = new CilentProxy();
this.rc = new rmiCilent();
this.rc.setId(RegisterIp);
this.rc.setPort(RegisterPort);
this.cp.setRmicilent(this.rc);
}
public void setPort(int selfPort) {
self.setPort(selfPort);
}
public int getPort() {
return self.getPort();
}
/*
*注册单项服务
*/
public void register(String name) {
List<String> list = new ArrayList<String>();
list.add(name);
IRegister ir = cp.getProxy(IRegister.class);//进行短连接注册中心,进行注册
ir.registServer(self, list);
}
/*
*注销本地服务
*/
public void LogoutResource() {
IRegister ir = cp.getProxy(IRegister.class);
ir.logOutServer(self);
}
/*
*注册多项服务
*/
public void registeAll(List<String> nameList) {
IRegister ir = cp.getProxy(IRegister.class);//进行短连接注册中心,进行注册
ir.registServer(self, nameList);
}
public static String getSelfIp() {
try {
InetAddress address = InetAddress.getLocalHost();
String ip = address.getHostAddress();
return ip;
} catch (UnknownHostException e) {
e.printStackTrace();
}
return null;
}
}
SenderServer
/*
*可以直接进行使用的资源接收端的入口类
*提供注册和注销资源的调用方法供用户使用
*/
@rmiInterface(rmiter = Isender.class)
public class SenderServer implements Isender{
private rmiServer sr;//作为短连接的服务器端,用于进行本地资源的发送
private ResourcePool rp;
private Provider provider;
public SenderServer() {
provider = new Provider();
rp = new ResourcePool();//对于这个ReourcePool来说,用于发送端存储提供给接收端的资源
sr = new rmiServer();
}
public void setPort(int port) {
provider.setPort(port);
}
public void start() {
sr.setPort(provider.getPort());
sr.start();
}
public void RegisteResource(String name) {
provider.register(name);
}
/*
*将默认路径上的所有资源都进行注册
*/
public void registeAllResource() {
//在此之前发送端已经进行设置默认的本地需要注册资源的路径
Set<String> resourceList = rp.getResourceName();
List<String> list = new ArrayList<String>();
for(String one : resourceList) {
list.add(one);
}
provider.registeAll(list);
}
public void LogoutResource() {
provider.LogoutResource();
}
/*
*将本地拥有的资源基本信息存在本地缓存中
*存储单项资源基本信息
*/
public void addResource(String resourceName) {
rp.addResource(resourceName);
//发送端将本地的资源存储到发送端缓存中
}
/*
*用户设置需要在缓存中存储本地下哪个目录下的资源
*resourceRoot表示为资源根目录
*之后可直接通过资源的名称可以直接将本地资源的基本信息存入缓存
*/
public void setResoureRoot(String resourceRoot) {//先将注册的资源进行整理
rp.setLocalRoot(resourceRoot);
}
/*
*响应接收端短连接响应的方法
*开启发送线程,链接接收端,并且进行片段发送
*/
@Override
public void send(NetNode receive, ResourceInfo ri) {
senderDetail sd = new senderDetail(receive, ri, rp);
new Thread(sd).start();
}
}
SenderDetail
资源发送端真正的资源发送的管理类。
public class SenderDetail implements Runnable{
//对于一个发送端来说事实上是一个短连接的过程,一次发送
private NetNode receive;
private Socket socket;
private DataOutputStream dos;
private ResourceInfo ri;
private Map<String, RandomAccessFile> rafPool;
private RandAccessFilePool rfp;
private ResourcePool rcp;
public SenderDetail(NetNode receive, ResourceInfo ri,ResourcePool rp) {
this.receive =receive;
this.rcp = rp;
rafPool = new HashMap<String, RandomAccessFile>();
String root = rp.getResourceInfo(ri.getResourceName()).getRoot();
this.ri = ri;//得到的为接收端发过来的资源,需要对本地的目录进行更改
this.ri.setRoot(root);
rfp = new RandAccessFilePool();
}
@Override
public void run() {
connectServer();
send();
close();
}
private void connectServer() {
try {
socket = new Socket(receive.getIp(), receive.getPort());
dos = new DataOutputStream(socket.getOutputStream());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void send() {
String root = this.ri.getRoot();
List<FileHead> headList = ri.getFileHeadList();
Map<Integer, FileInfo> fileInfoMap = ri.getFileInfoMap();
int i;
for( i = 0; i < headList.size(); i++) {
FileHead fh = headList.get(i);
String address = root + fileInfoMap.get(fh.getFileHandle()).getFileRoot();
RandomAccessFile raf;
try {
raf = rfp.getReadRaf(address);
int size = fh.getSectionLength();
byte[] bytes = new byte[size];
raf.seek(fh.getOffset());
raf.read(bytes);
TransferDetail td = new TransferDetail();
td.writeBytes(dos, fh.getHeadBytes());
td.writeBytes(dos, bytes);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
closeFile();
}
private void close() {
try {
if (dos != null) {
dos.close();
}
} catch (IOException e) {
} finally {
dos = null;
}
try {
if (socket != null && !socket.isClosed()) {
socket.close();
}
} catch (IOException e) {
} finally {
socket = null;
}
}
private void closeFile() {
for (RandomAccessFile raf : rafPool.values()) {
try {
raf.close();
} catch (IOException e) {
}
}
}
}
ResourcePool.
资源发送端的本地缓存,将本地磁盘的资源的基本信息进行缓存,减少了不必要的IO操作,节省了系统资源,加快了访问速度。
public class ResourcePool {
//对于每个发送端来说,都要自己的一个本地资源库
private static final Map<String, ResourceInfo> resourcePool = new HashMap<String, ResourceInfo>();;
private static final String DEFAULT_LOCAL_ROOT = "E:\\KSG\\";//每个发送端应该明确自己的资源默认的根路径
private String LocalRoot = DEFAULT_LOCAL_ROOT;//有默认值,但是发送端可以进行设置
//在这里仅仅表示的是服务器端资源的根路径
public ResourcePool() {
}
//通过查找本地路径生成这个map,
public String getLocalRoot() {
return LocalRoot;
}
public void setLocalRoot(String localRoot) {
LocalRoot = localRoot;
}
public void addResource(String resourceName) {
//例如这里使用输入QQ类似的民称
//则应该在"E:\\KSG\\QQ"这个文件下进行资源的查找,形成ResourceInfo,并且在
//resource中的root就是E:\\KSG,那么接收端收到相关的resource之后,需要将root改为
//自定义的root,因为当接收端拥有完整的资源后,接收端可能变为下一个发送端,它在发送的时候
//也需要确定自己的root,
//TODO 根据路径进行多个文件的查找组成一个文件的map,并且构造出resource
String findAdress = LocalRoot + resourceName;//发送端拥有资源的本地全称
ResourceInfo ri = new ResourceInfo();
ri.setResourceName(resourceName);
ri.setRoot(LocalRoot);
ri.setVersion(0);
//根据资源的路径,得到资源的一些信息,因为一个资源包括很多文件,或者是目录,那么需要
//将资源的左右文件记录在案,并且需要知道每个文件的具体的一些信息,长度,相对路径
makeResource(findAdress, ri, resourceName);
}
public void makeResource(String address, ResourceInfo ri, String ResourceName) {
File file = new File(address);
if(!file.exists()) {//表明资源文件地址错误或没有
return;
}
File[] files = file.listFiles();
for(int i = 0; i < files.length; i++) {
File currentfile = files[i];
if(currentfile.isFile()) {
String currentPath = files[i].getAbsolutePath();
//fileINfo用来描述的是资源下每一个文件的的具体信息
//包括文件的相对地址,文件的长度,因为这是为后期在资源的传送的时候确保完整的一个条件
FileInfo fi = new FileInfo();
//得到当前的相对路经
fi.setFileRoot(currentPath.replace(LocalRoot, ""));//相对路径为当前路径去掉绝对路径
fi.setFileLength(currentfile.length());
int fileHash = fi.hashCode();
//设置每个文件的句柄,每个文件的句柄采用的是文件的相对路径和文件的长度进行衡量
fi.setFileHandle(fileHash);
ri.addFileInfo(fileHash,fi);
resourcePool.put(ResourceName, ri);
}else {
String name = files[i].getName();
String path = address + "\\" + name;
makeResource(path, ri, ResourceName);
}
}
}
public ResourceInfo getResourceInfo(String ResourceName) {
return resourcePool.get(ResourceName);
}
public Set<String> getResourceName(){
return resourcePool.keySet();
}
}