同步了这些天在CUTV客户端做的修改。

This commit is contained in:
free will committed 2020-04-28 23:02:40 +08:00
1 parent 41d1a74acf
commit dc40211f34
26 files changed
+1466 -327

No files matched your search

Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
#commit changes: delete a prefix
#Fri Apr 17 20:54:49 CST 2020
View File
Whitespace-only changes.
+3 -3
View File
@@ -1,7 +1,7 @@
#\u4FEE\u6539\u914D\u7F6E\u6587\u4EF6
#Wed Apr 08 00:41:05 CST 2020
KeyName=/testKey_v3
loginUserName=466D1203678EFB16BE85C8A02E1486B6
#Tue Apr 28 22:56:20 CST 2020
KeyName=/王锋
loginUserName=B94DF2C54EDEA80B50A94EA603DB833E
ndnBlockChainIPAddress=116.77.74.139
ServerIPAddress=116.77.74.139
ThreadNumberForFileTransfer=5
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+52 -16
View File
@@ -1,12 +1,14 @@
package cn.minoa;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import cn.minoa.dataRequestInterface.*;
import cn.minoa.model.*;
import cn.minoa.util.FileUtil;
import cn.minoa.util.GenerateSettingFiles;
import cn.minoa.util.LoggerUtil;
import cn.minoa.util.StringByteLengthUtil;
import cn.minoa.view.NavigationBarController;
@@ -141,11 +143,19 @@ public class MainApp extends Application {
private Stage uploadFileDialogStage;
// 下载文件进度条stage
private Stage downloadFileDialogStage;
// 进度监听线程
private Thread listenThread;
// 上传客户端
private UpLoadClientBPRenewal upLoadClient;
// 下载客户端
private DownLoadClientBPRenewal downLoadClient;
// 决定心跳包是否需要判断登录状态是否失效
public boolean isNeedKnowLoginStatus=false;
public MainApp() {
// 初始化ndn目录
GenerateSettingFiles.generateInitFiles();
// 加载配置文件
loadSettingProperties();
// 初始化一些数据
@@ -200,8 +210,11 @@ public class MainApp extends Application {
if (inputStream == null) {
System.out.println("没有找到配置文件...");
}
// 解决中文编码乱码问题
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(inputStream);
// settingProperties.load(inputStream);
settingProperties.load(bf);
String serverIPAddress = settingProperties.getProperty("ServerIPAddress");
String serverPortAddress = settingProperties.getProperty("ServerPortAddress");
String NDNBlockChainIPAddressString=settingProperties.getProperty("ndnBlockChainIPAddress");
@@ -426,6 +439,13 @@ public class MainApp extends Application {
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
isCancelFileTransferFlag = true;
// 再次关闭进度条监听线程
listenThread.interrupt();
// 保存断点信息
downLoadClient.setPointInfo();
// 关闭该次传输
downLoadClient.closeSelf();
// 弹窗关闭
downloadFileDialogStage.close();
}
});
@@ -446,10 +466,12 @@ public class MainApp extends Application {
Long startTime = System.currentTimeMillis();
// 滑动窗口协议下载文件
// DownLoadClient downLoadClient = new DownLoadClient(filename,localDir,sliceNum);
DownLoadClientBasedFacePool downLoadClient=new DownLoadClientBasedFacePool(filename,
// DownLoadClientBasedFacePool downLoadClient=new DownLoadClientBasedFacePool(filename,
// localDir,sliceNum,threadNumberForFileTransfer);
downLoadClient=new DownLoadClientBPRenewal(filename,
localDir,sliceNum,threadNumberForFileTransfer);
//启动一个线程监听更新的传输进度值
Thread listenThread = new Thread(new Runnable() {
listenThread = new Thread(new Runnable() {
@Override
public void run() {
Long sliceNumLong=sliceNum.longValue();
@@ -618,6 +640,13 @@ public class MainApp extends Application {
public void handle(ActionEvent event) {
// 手动取消了传输
isCancelFileTransferFlag = true;
// 再次关闭进度条监听线程
listenThread.interrupt();
// 上传信息保存到本地
upLoadClient.setPointInfo();
// 关闭该次传输
upLoadClient.closeSelf();
// 关闭弹窗
uploadFileDialogStage.close();
}
});
@@ -648,10 +677,14 @@ public class MainApp extends Application {
Long startTime = System.currentTimeMillis();
// 滑动窗口协议上传文件
// UpLoadClient upLoadClient = new UpLoadClient(file, serverpath);
UpLoadClientBasedFacePool upLoadClient=new UpLoadClientBasedFacePool(file,
// 增加了facepool支持的滑动窗口协议
// UpLoadClientBasedFacePool upLoadClient=new UpLoadClientBasedFacePool(file,
// serverpath,threadNumberForFileTransfer);
// 进一步增加了断点续传支持
upLoadClient=new UpLoadClientBPRenewal(file,
serverpath,threadNumberForFileTransfer);
//启动一个线程监听更新的传输进度值
Thread listenThread = new Thread(new Runnable() {
listenThread = new Thread(new Runnable() {
@Override
public void run() {
long filelen = file.length();
@@ -707,6 +740,7 @@ public class MainApp extends Application {
System.out.println("已成功将文件" + file.getAbsolutePath() + "上传至服务器" + serverpath + "目录下。");
// String serverFilePath = serverpath + MinoaDataAPI.getPureFileNameFromWindows(file.getAbsolutePath());
// ECOSUtil.sendUploadFileEndSignal(serverFilePath);
// ECOSUtil.sendECOSUploadEndSignal(serverFilePath);
} else {
System.out.println("由于未知原因,本地文件" + file.getAbsolutePath() + "上传服务器失败。");
}
@@ -723,10 +757,10 @@ public class MainApp extends Application {
public boolean uploadFileToServerSharedFolder(File file) {
// Integer res=loginerController.sendFileToServer(file, this.sharedFileServerPath);
Long startTime = System.currentTimeMillis();
UpLoadClientBasedFacePool upLoadClient = new UpLoadClientBasedFacePool(
UpLoadClientBPRenewal upLoadClient = new UpLoadClientBPRenewal(
file,this.sharedFileServerPath,threadNumberForFileTransfer);
// 下载文件
boolean res = ((UpLoadClientBasedFacePool) upLoadClient).uploadData();
boolean res = upLoadClient.uploadData();
Long endTime = System.currentTimeMillis();
System.out.println("耗时:" + (endTime - startTime) + "ms");
return res;
@@ -897,15 +931,17 @@ public class MainApp extends Application {
// 判断是否是登录状态,且账号密码是正确的
boolean m_flag=false;
boolean isLoginning= KeepLoginStatus.getLogineStatus();
Loginer m_loginer=KeepLoginStatus.getLoginerInfo();
if((isLoginning==true)&&(m_loginer.getUserName()!=null)&&(m_loginer.getPassWord()!=null)){
System.out.println("login status: "+isLoginning);
System.out.println("loginer name: "+m_loginer.getUserName());
System.out.println("loginer password: "+m_loginer.getPassWord());
String loginString=loginerController.getLoginJsonString(
m_loginer.getUserName(),m_loginer.getPassWord());
if(loginerController.checkPass(loginString)){
m_flag=true;
if(isLoginning==true){
Loginer m_loginer=KeepLoginStatus.getLoginerInfo();
if((m_loginer.getUserName()!=null)&&(m_loginer.getPassWord()!=null)){
System.out.println("login status: "+isLoginning);
System.out.println("loginer name: "+m_loginer.getUserName());
System.out.println("loginer password: "+m_loginer.getPassWord());
String loginString=loginerController.getLoginJsonString(
m_loginer.getUserName(),m_loginer.getPassWord());
if(loginerController.checkPass(loginString)){
m_flag=true;
}
}
}
@@ -160,7 +160,8 @@ public class CongestionWindow {
public void cwndDecrease(){
synchronized (this){
if(nIndata >= nSupress){
this.thresh = Math.floor(this.cwnd/2);
// this.thresh = Math.floor(this.cwnd/2);
this.thresh = this.cwnd/2;
this.cwnd = this.thresh;
nSupress = (int)(nOutInterest + rate*(nOutInterest - nIndata));
}
@@ -1,6 +1,8 @@
package cn.minoa.dataRequestInterface;
import cn.minoa.MainApp;
import cn.minoa.model.BPRInfo;
import cn.minoa.util.FileBPRUtil;
import net.named_data.jndn.*;
import net.named_data.jndn.security.KeyChain;
import net.named_data.jndn.security.SecurityException;
@@ -20,7 +22,7 @@ import java.util.concurrent.atomic.AtomicLong;
* @description
* @date 2020-03-22 18:28
*/
public class DownLoadClientBasedFacePool {
public class DownLoadClientBPRenewal {
// 下载前缀
private String orderPrefix = "/downloadFile";
@@ -51,13 +53,23 @@ public class DownLoadClientBasedFacePool {
// 收到回复的数量
public AtomicLong recvCount = new AtomicLong(0);
// 断点续传:此偏移量/序号之前的文件部分已经全部传输成功
private AtomicLong successPoint=new AtomicLong(0);
// 断点续传:point及其之后的兴趣包,已经传输成功的兴趣包序号
private Map<Long, Boolean> successList = new ConcurrentHashMap<>();
// 断点续传:当前文件哈希值
private String fileHashString;
//发送的数据是否发送成功,key:第几个数据片,从0开始,value:该数据片超时次数
private Map<Integer, Integer> timeOutNums = new ConcurrentHashMap<>();
// 超时重传上限数值,某个兴趣包的重传次数超过此数值,则放弃重传,直接返回false
private Integer timeoutCeil=15;
public DownLoadClientBasedFacePool(String filename, String localDir,
Integer sliceNumber, Integer facepoolnumber) {
// 标记该次传输是否关闭
private boolean isClosed;
public DownLoadClientBPRenewal(String filename, String localDir,
Integer sliceNumber, Integer facepoolnumber) {
this.filename = filename;
this.localDir = localDir;
System.out.println("localDir: "+this.localDir);
@@ -65,6 +77,59 @@ public class DownLoadClientBasedFacePool {
this.facePool=new FacePool(facepoolnumber);
this.facePool.start(MinoaDataAPI.minoaServerIpString, MinoaDataAPI.minoaServerPortInteger);
System.out.println("***********FacePool中并发数:"+facepoolnumber+"***********");
fileHashString=filename+"_"+sliceNumber;
isClosed=false;
}
/*
* 传入一个刚被后台成功响应的兴趣包序号,
* 判断[point,current]之间的兴趣包序号是否全部被成功响应
*/
private boolean isAllOK(Long point,Long currentNo){
for(Long i=point;i<=currentNo;i++){
if(!successList.containsKey(i)){
return false;
}
}
return true;
}
// 移除successList中已经成功发送的部分,减少内存占用
private void mvSuccessNum(Long fromNo,Long toNo){
for(Long i=fromNo;i<=toNo;i++){
successList.remove(i);
}
}
// 对每个成功收到200应答的兴趣包执行如下程序,
// 以维持断点续传的功能
private void refreshSuccessPoint(Long sliceNo){
// 当前断点
Long point=successPoint.get();
// 加入successList
successList.put(sliceNo,true);
// 如果当前断点到新收到数据包之间的兴趣包全部成功响应,
// 更新断点,并清理内存
if(isAllOK(point,sliceNo)){
successPoint.getAndSet(sliceNo+1);
mvSuccessNum(point,sliceNo);
}
}
// 将本次传输的断点信息保存到本地
public void setPointInfo(){
String fileName= MinoaDataAPI.getPureFileName(filename);
FileBPRUtil.setUploadBreakPointInfo(
fileHashString,fileName,localDir,successPoint.get());
System.out.println("保存断点信息成功!!!");
}
// 移除已经上传成功的文件断点信息
private void rmPointInfo(){
if(FileBPRUtil.isHaveUploadBreakPointInfo(fileHashString)){
FileBPRUtil.deleteUploadBreakPointInfo(fileHashString);
}
}
/**
@@ -81,6 +146,21 @@ public class DownLoadClientBasedFacePool {
return false;
}
// 由于点击取消传输之后弹窗关闭,
// 该文件类可能会继续发送数据,或有其它继续执行的代码
// 这里增加一个函数进行关闭操作
public void closeSelf(){
try {
this.randomAccessFile.close();
System.out.println("本地文件关闭");
} catch (IOException e) {
System.out.println("取消传输时关闭文件报错:"+e.getMessage());
}
this.facePool.shutdownNow();
this.isClosed=true;
}
/**
* 下载数据的主函数
*
@@ -96,21 +176,45 @@ public class DownLoadClientBasedFacePool {
e.printStackTrace();
}
while (true) {
//判断是否已经上传安成
// 判断是否有断点续传记录
if(FileBPRUtil.isHaveUploadBreakPointInfo(fileHashString)){
// 有记录,则判断文件名和服务器地址是否一致
BPRInfo bprInfo=FileBPRUtil.getUploadBreakPointInfo(fileHashString);
String fileName= MinoaDataAPI.getPureFileName(filename);
if((!(bprInfo==null))
&&bprInfo.getFileName().equals(fileName)
&&bprInfo.getFileLocator().equals(localDir)){
// 都一致,则更新recvCount\currentOffset\successPoint
System.out.println("即将开始断点续传...");
recvCount.getAndSet(bprInfo.getPoint());
currentSliceNo=(int)recvCount.get();
successPoint.getAndSet(bprInfo.getPoint());
}else{
System.out.println("即将开始文件下载...");
}
}else {
System.out.println("即将开始文件下载...");
}
while (!isClosed) {
//判断是否已经下载完成
if (recvCount.longValue()>=this.sliceNumber) {
break;
}
// 判断是否已经被用户终止上传
// 判断是否已经被用户终止下载
if(MainApp.isCancelFileTransferFlag){
System.out.println("用户已主动中断下载");
try {
this.randomAccessFile.close();
System.out.println("本地文件关闭");
} catch (IOException e) {
e.printStackTrace();
}
// try {
// this.randomAccessFile.close();
// System.out.println("本地文件关闭");
// } catch (IOException e) {
// e.printStackTrace();
// }
// this.facePool.shutdownNow();
closeSelf();
// 保存断点信息
setPointInfo();
return false;
}
@@ -143,25 +247,31 @@ public class DownLoadClientBasedFacePool {
if(isTimeOut()){
System.out.println("丢包超过阈值: "+timeoutCeil+" ,文件传输主动中断");
this.facePool.shutdownNow();
try {
this.randomAccessFile.close();
System.out.println("本地文件关闭");
} catch (IOException e) {
e.printStackTrace();
}
// try {
// this.randomAccessFile.close();
// System.out.println("本地文件关闭");
// } catch (IOException e) {
// e.printStackTrace();
// }
// this.facePool.shutdownNow();
closeSelf();
// 保存断点信息
setPointInfo();
return false;
}
}
this.facePool.shutdownNow();
try {
this.randomAccessFile.close();
System.out.println("本地文件关闭");
} catch (IOException e) {
e.printStackTrace();
}
// try {
// this.randomAccessFile.close();
// System.out.println("本地文件关闭");
// } catch (IOException e) {
// e.printStackTrace();
// }
// this.facePool.shutdownNow();
closeSelf();
// 更新断点信息
rmPointInfo();
return true;
}
@@ -240,10 +350,11 @@ public class DownLoadClientBasedFacePool {
@Override
public void onData(Interest interest, Data data) {
// 将文件数据片写入本地文件
try {
synchronized (randomAccessFile) {
System.out.println("开始写入文件数据分片... :" + localDir + localName);
if(!isClosed) {
// 将文件数据片写入本地文件
try {
synchronized (randomAccessFile) {
System.out.println("开始写入文件数据分片... :" + localDir + localName);
// RandomAccessFile randomAccessFile = new RandomAccessFile(localDir + localName, "rw");
// int contentSize = data.getContent().size();
// System.out.println("该数据分片长度为:" + contentSize);
@@ -251,80 +362,93 @@ public class DownLoadClientBasedFacePool {
// for (int i = 0; i < contentSize; i++) {
// content[i] = data.getContent().buf().get(i);
// }
// 设置数据分片写入到文件的起点位置
randomAccessFile.seek(sliceNo * MainApp.sliceSize);
// 写入数据分片
randomAccessFile.write(data.getContent().getImmutableArray());
// 设置数据分片写入到文件的起点位置
long offset=((long)sliceNo) * ((long) MainApp.sliceSize);
try{
randomAccessFile.seek(offset);
}catch (IOException e){
// 说明文件流已经关闭,则不继续执行
return ;
}
// 写入数据分片
randomAccessFile.write(data.getContent().getImmutableArray());
// randomAccessFile.write(content, 0, contentSize);
// randomAccessFile.close();
System.out.println("写入文件数据分片完毕:" + localDir + localName);
System.out.println("写入文件数据分片完毕:" + localDir + localName);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// 滑动窗口:flight--
congestionWindow.inFlightDecrease();
// 收到成功数据的数量++
recvCount.incrementAndGet();
// 滑动窗口:inData++
congestionWindow.nIndataIncrease();
// 刷新断点
refreshSuccessPoint((long)sliceNo);
System.out.println("第" + sliceNo + "片下载成功!");
// 处理拥塞:拥塞标记返回值,无意义,大于0就表示拥塞,直接进行窗口减小操作即可
if (data.getCongestionMark() > 0) {
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&网络拥塞,滑动窗口减小,getCongestionMark:" + data.getCongestionMark());
// 滑动窗口:cwndDecrease()
congestionWindow.cwndDecrease();
} else {
// 滑动窗口:cwndIncrease()
congestionWindow.cwndIncrease();
}
if (timeOutNums.containsKey(this.sliceNo)) {
timeOutNums.remove(this.sliceNo);
}
// 处理完成
isFinished = true;
}
// 滑动窗口:flight--
congestionWindow.inFlightDecrease();
// 收到成功数据的数量++
recvCount.incrementAndGet();
// 滑动窗口:inData++
congestionWindow.nIndataIncrease();
System.out.println("第" + sliceNo + "片下载成功!");
// 处理拥塞:拥塞标记返回值,无意义,大于0就表示拥塞,直接进行窗口减小操作即可
if (data.getCongestionMark() > 0) {
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&网络拥塞,滑动窗口减小,getCongestionMark:" + data.getCongestionMark());
// 滑动窗口:cwndDecrease()
congestionWindow.cwndDecrease();
}else{
// 滑动窗口:cwndIncrease()
congestionWindow.cwndIncrease();
}
if(timeOutNums.containsKey(this.sliceNo)){
timeOutNums.remove(this.sliceNo);
}
// 处理完成
isFinished = true;
}
// 处理兴趣包超时
@Override
public void onTimeout(Interest interest) {
// 滑动窗口:flight--
congestionWindow.inFlightDecrease();
// 加入失败队列
failedSlice.add(sliceNo);
// 打印超时信息
System.out.println("########## Time out for interest " + interest.getName()+"###########");
if(!isClosed) {
// 滑动窗口:flight--
congestionWindow.inFlightDecrease();
// 加入失败队列
failedSlice.add(sliceNo);
// 打印超时信息
System.out.println("########## Time out for interest " + interest.getName() + "###########");
if(timeOutNums.containsKey(this.sliceNo)){
int value = timeOutNums.get(this.sliceNo) + 1;
timeOutNums.put(this.sliceNo,value);
}else{
timeOutNums.put(this.sliceNo,1);
if (timeOutNums.containsKey(this.sliceNo)) {
int value = timeOutNums.get(this.sliceNo) + 1;
timeOutNums.put(this.sliceNo, value);
} else {
timeOutNums.put(this.sliceNo, 1);
}
// 处理完成
isFinished = true;
}
// 处理完成
isFinished = true;
}
// 处理收到一个Nack包
@Override
public void onNetworkNack(Interest interest, NetworkNack networkNack){
congestionWindow.inFlightDecrease();
failedSlice.add(sliceNo);
if(timeOutNums.containsKey(this.sliceNo)){
int value = timeOutNums.get(this.sliceNo) + 1;
timeOutNums.put(this.sliceNo,value);
}else{
timeOutNums.put(this.sliceNo,1);
public void onNetworkNack(Interest interest, NetworkNack networkNack) {
if (!isClosed) {
congestionWindow.inFlightDecrease();
failedSlice.add(sliceNo);
if (timeOutNums.containsKey(this.sliceNo)) {
int value = timeOutNums.get(this.sliceNo) + 1;
timeOutNums.put(this.sliceNo, value);
} else {
timeOutNums.put(this.sliceNo, 1);
}
// 打印超时信息
System.out.println("########## Nack for interest " + interest.getName()
+ ", Nack: " + networkNack.toString());
isFinished = true;
}
// 打印超时信息
System.out.println("########## Nack for interest " + interest.getName()
+", Nack: "+networkNack.toString());
isFinished=true;
}
}
@@ -2,15 +2,14 @@ package cn.minoa.dataRequestInterface;
import net.named_data.jndn.Name;
import net.named_data.jndn.security.KeyChain;
import net.named_data.jndn.security.pib.Pib;
import net.named_data.jndn.security.pib.PibIdentity;
import net.named_data.jndn.security.pib.PibImpl;
import net.named_data.jndn.security.pib.PibSqlite3;
import net.named_data.jndn.security.pib.*;
import net.named_data.jndn.security.tpm.Tpm;
import net.named_data.jndn.security.tpm.TpmBackEnd;
import net.named_data.jndn.security.tpm.TpmBackEndFile;
import net.named_data.jndn.security.v2.CertificateV2;
import java.io.File;
public enum KeyManager {
INSTANCE;
private KeyChain keyChain = null;
@@ -42,8 +41,10 @@ public enum KeyManager {
private KeyChain getOrBuildKeyChain(String identityName) throws
KeyChain.Error, PibImpl.Error, Pib.Error, Tpm.Error, TpmBackEnd.Error, CertificateV2.Error {
KeyChain keyChain = null;
PibSqlite3 pibSqlite3 = new PibSqlite3("./ndn/pid");
TpmBackEndFile tpmBackEndFile = new TpmBackEndFile("./ndn/tpm");
PibSqlite3 pibSqlite3=new PibSqlite3("." + File.separator + "ndn"+
File.separator+"pid");
TpmBackEndFile tpmBackEndFile = new TpmBackEndFile("." + File.separator + "ndn"+
File.separator+"tpm");
try {
keyChain = new KeyChain(pibSqlite3, tpmBackEndFile);
PibIdentity identity = keyChain.getPib().getIdentity(new Name(identityName));
@@ -63,8 +64,10 @@ public enum KeyManager {
public boolean isInKeyChain(String identityName) throws
KeyChain.Error, PibImpl.Error, Pib.Error, Tpm.Error, TpmBackEnd.Error, CertificateV2.Error {
KeyChain keyChain = null;
PibSqlite3 pibSqlite3 = new PibSqlite3("./ndn/pid");
TpmBackEndFile tpmBackEndFile = new TpmBackEndFile("./ndn/tpm");
PibSqlite3 pibSqlite3=new PibSqlite3("." + File.separator + "ndn"+
File.separator+"pid");
TpmBackEndFile tpmBackEndFile = new TpmBackEndFile("." + File.separator + "ndn"+
File.separator+"tpm");
try {
keyChain = new KeyChain(pibSqlite3, tpmBackEndFile);
PibIdentity identity = keyChain.getPib().getIdentity(new Name(identityName));
@@ -1,6 +1,9 @@
package cn.minoa.dataRequestInterface;
// 在原来基于FacePool上传文件的基础上,
// 增加断点续传功能
import cn.minoa.MainApp;
import cn.minoa.model.BPRInfo;
import cn.minoa.util.FileBPRUtil;
import cn.minoa.util.StringByteLengthUtil;
import net.named_data.jndn.*;
import net.named_data.jndn.security.KeyChain;
@@ -24,7 +27,7 @@ import java.util.concurrent.atomic.AtomicLong;
* @description
* @date 2020-03-22 18:28
*/
public class UpLoadClientBasedFacePool {
public class UpLoadClientBPRenewal {
private String orderPrefix = "/uploadFile";
@@ -49,24 +52,104 @@ public class UpLoadClientBasedFacePool {
private ConcurrentLinkedQueue<Long> failedSlice = new ConcurrentLinkedQueue<>();
//发送的数据是否发送成功,key:第几个数据片,从0开始,value:是否发送成功
private Map<Long, Boolean> sendRes = new ConcurrentHashMap<>();
// private Map<Long, Boolean> sendRes = new ConcurrentHashMap<>();
//收到回复的数量
public AtomicLong recvCount = new AtomicLong(0);
// 断点续传:此偏移量/序号之前的文件部分已经全部传输成功
private AtomicLong successPoint=new AtomicLong(0);
// 断点续传:point及其之后的兴趣包,已经传输成功的兴趣包序号
private Map<Long, Boolean> successList = new ConcurrentHashMap<>();
// 断点续传:当前文件哈希值
private String fileHashString;
//发送的数据是否发送成功,key:第几个数据片,从0开始,value:该数据片超时次数
private Map<Long, Integer> timeOutNums = new ConcurrentHashMap<>();
// 超时重传上限数值,某个兴趣包的重传次数超过此数值,则放弃重传,直接返回false
private Integer timeoutCeil=15;
public UpLoadClientBasedFacePool(File file, String serverPath, Integer facepoolnumber){
// 标记该次传输的状态
private boolean isClosed;
public UpLoadClientBPRenewal(File file, String serverPath, Integer facepoolnumber){
this.file = file;
this.serverPath = serverPath;
this.facePool=new FacePool(facepoolnumber);
this.facePool.start(MinoaDataAPI.minoaServerIpString, MinoaDataAPI.minoaServerPortInteger);
System.out.println("***********FacePool中并发数:"+facepoolnumber+"***********");
// fileHashString= EncryptionUtil.getFileHash(file.getAbsolutePath());
fileHashString= MinoaDataAPI.getPureFileNameFromWindows(file.getAbsolutePath())
+"_"+file.length();
isClosed=false;
}
// 由于点击取消传输之后弹窗关闭,
// 该文件类可能会继续发送数据,或有其它继续执行的代码
// 这里增加一个函数进行关闭操作
public void closeSelf(){
try {
this.randomAccessFile.close();
System.out.println("本地文件关闭");
} catch (IOException e) {
System.out.println("取消传输时关闭文件报错:"+e.getMessage());
}
this.facePool.shutdownNow();
this.isClosed=true;
}
/*
* 传入一个刚被后台成功响应的兴趣包序号,
* 判断[point,current]之间的兴趣包序号是否全部被成功响应
*/
private boolean isAllOK(Long point,Long currentNo){
for(Long i=point;i<=currentNo;i++){
if(!successList.containsKey(i)){
return false;
}
}
return true;
}
// 移除successList中已经成功发送的部分,减少内存占用
private void mvSuccessNum(Long fromNo,Long toNo){
for(Long i=fromNo;i<=toNo;i++){
successList.remove(i);
}
}
// 对每个成功收到200应答的兴趣包执行如下程序,
// 以维持断点续传的功能
private void refreshSuccessPoint(Long sliceNo){
// 当前断点
Long point=successPoint.get();
// 加入successList
successList.put(sliceNo,true);
// 如果当前断点到新收到数据包之间的兴趣包全部成功响应,
// 更新断点,并清理内存
if(isAllOK(point,sliceNo)){
successPoint.getAndSet(sliceNo+1);
mvSuccessNum(point,sliceNo);
}
}
// 将本次传输的断点信息保存到本地
public void setPointInfo(){
String fileName= MinoaDataAPI.getPureFileNameFromWindows(file.getAbsolutePath());
FileBPRUtil.setUploadBreakPointInfo(
fileHashString,fileName,serverPath,successPoint.get());
System.out.println("保存断点信息成功!!!");
}
// 移除已经上传成功的文件断点信息
private void rmPointInfo(){
if(FileBPRUtil.isHaveUploadBreakPointInfo(fileHashString)){
FileBPRUtil.deleteUploadBreakPointInfo(fileHashString);
}
}
/**
* 判断是否含有超时次数超过阈值的
* @return
@@ -94,14 +177,35 @@ public class UpLoadClientBasedFacePool {
e.printStackTrace();
}
// 初始化sliceNumbers
if(file.length()% MainApp.sliceSize == 0){
sliceNumbers = file.length()/ MainApp.sliceSize;
}else{
sliceNumbers = file.length()/ MainApp.sliceSize + 1;
}
while(true){
//判断是否已经上传安成
// 判断是否有断点续传记录
if(FileBPRUtil.isHaveUploadBreakPointInfo(fileHashString)){
// 有记录,则判断文件名和服务器地址是否一致
BPRInfo bprInfo=FileBPRUtil.getUploadBreakPointInfo(fileHashString);
String fileName= MinoaDataAPI.getPureFileNameFromWindows(file.getAbsolutePath());
if((!(bprInfo==null))
&&bprInfo.getFileName().equals(fileName)
&&bprInfo.getFileLocator().equals(serverPath)){
// 都一致,则更新recvCount\currentOffset\successPoint
System.out.println("即将开始断点续传...");
recvCount.getAndSet(bprInfo.getPoint());
currentOffset=recvCount.get()* MainApp.sliceSize;
successPoint.getAndSet(bprInfo.getPoint());
}else{
System.out.println("即将开始文件上传...");
}
}else {
System.out.println("即将开始文件上传...");
}
while(!isClosed){
// 判断是否已经上传完成
if(sliceNumbers <= recvCount.longValue()){
break;
}
@@ -109,12 +213,16 @@ public class UpLoadClientBasedFacePool {
// 判断是否已经被用户终止上传
if(MainApp.isCancelFileTransferFlag){
System.out.println("用户已主动中断上传");
try {
this.randomAccessFile.close();
System.out.println("本地文件关闭");
} catch (IOException e) {
e.printStackTrace();
}
// try {
// this.randomAccessFile.close();
// System.out.println("本地文件关闭");
// } catch (IOException e) {
// e.printStackTrace();
// }
// this.facePool.shutdownNow();
closeSelf();
// 保存断点信息
setPointInfo();
return false;
}
@@ -145,30 +253,35 @@ public class UpLoadClientBasedFacePool {
}
congestionWindow.inFlightIncrease();
congestionWindow.nOutInterestIncrease();
}
if(isTimeOut()){
System.out.println("丢包超过阈值: "+timeoutCeil+" ,文件传输主动中断");
this.facePool.shutdownNow();
try {
this.randomAccessFile.close();
System.out.println("本地文件关闭");
} catch (IOException e) {
e.printStackTrace();
}
// try {
// this.randomAccessFile.close();
// System.out.println("本地文件关闭");
// } catch (IOException e) {
// e.printStackTrace();
// }
// this.facePool.shutdownNow();
closeSelf();
// 保存断点信息
setPointInfo();
return false;
}
}
try {
this.randomAccessFile.close();
System.out.println("本地文件关闭");
} catch (IOException e) {
e.printStackTrace();
}
this.facePool.shutdownNow();
// try {
// this.randomAccessFile.close();
// System.out.println("本地文件关闭");
// } catch (IOException e) {
// e.printStackTrace();
// }
// this.facePool.shutdownNow();
closeSelf();
// 更新本地断点信息
rmPointInfo();
return true;
}
@@ -224,7 +337,12 @@ public class UpLoadClientBasedFacePool {
synchronized (randomAccessFile) {
// RandomAccessFile randomAccessFile = new RandomAccessFile(localFilePath, "rw");
// 设置文件的读取起点
randomAccessFile.seek(offset);
try{
randomAccessFile.seek(offset);
}catch (IOException e){
// 说明文件流已经关闭,则不继续执行
return ;
}
// 尝试读取数据
int readLen = randomAccessFile.read(content, 0, 7000);
int jsonLen = StringByteLengthUtil.getByteLength(orderInfo.getJsonString());
@@ -296,41 +414,44 @@ public class UpLoadClientBasedFacePool {
@Override
public void onData(Interest interest, Data data){
responseData.setResponseData(data.getContent().toString());
JSONObject jsonObject = responseData.praseRequestData();
if (!isClosed) {
responseData.setResponseData(data.getContent().toString());
JSONObject jsonObject = responseData.praseRequestData();
congestionWindow.inFlightDecrease();
// 解析数据,是否成功上传
Integer codeInteger = null;
try {
codeInteger = jsonObject.getInt("code");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (codeInteger == 200) {
recvCount.incrementAndGet();
congestionWindow.cwndIncrease();
System.out.println("第" + sliceNum + "片上传成功!");
}else{
failedSlice.add(sliceNum* MainApp.sliceSize);
System.out.println("第" + sliceNum + "片上传失败!");
}
//拥塞标记返回值,无意义,大于0就表示拥塞,直接进行窗口减小操作即可
if(data.getCongestionMark() > 0){
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&网络拥塞,滑动窗口减小,getCongestionMark:" + data.getCongestionMark());
congestionWindow.cwndDecrease();
}else{
//如果没有检测到拥塞,则增加窗口
congestionWindow.nIndataIncrease();
}
congestionWindow.inFlightDecrease();
// 解析数据,是否成功上传
Integer codeInteger = null;
try {
codeInteger = jsonObject.getInt("code");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (codeInteger == 200) {
recvCount.incrementAndGet();
congestionWindow.cwndIncrease();
// 刷新断点
refreshSuccessPoint(sliceNum);
System.out.println("第" + sliceNum + "片上传成功!");
} else {
failedSlice.add(sliceNum * MainApp.sliceSize);
System.out.println("第" + sliceNum + "片上传失败!");
}
//拥塞标记返回值,无意义,大于0就表示拥塞,直接进行窗口减小操作即可
if (data.getCongestionMark() > 0) {
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&网络拥塞,滑动窗口减小,getCongestionMark:" + data.getCongestionMark());
congestionWindow.cwndDecrease();
} else {
//如果没有检测到拥塞,则增加窗口
congestionWindow.nIndataIncrease();
}
if(timeOutNums.containsKey(sliceNum)){
timeOutNums.remove(sliceNum);
if (timeOutNums.containsKey(sliceNum)) {
timeOutNums.remove(sliceNum);
}
isFinished = true;
}
isFinished = true;
}
public int callbackCount = 0 ;
@@ -349,18 +470,20 @@ public class UpLoadClientBasedFacePool {
@Override
public void onTimeout(Interest interest){
congestionWindow.inFlightDecrease();
failedSlice.add(upLoadData.sliceNum* MainApp.sliceSize);
callbackCount ++ ;
System.out.println("Time out for interest " + interest.getName());
upLoadData.isFinished = false;
if (!isClosed) {
congestionWindow.inFlightDecrease();
failedSlice.add(upLoadData.sliceNum * MainApp.sliceSize);
callbackCount++;
System.out.println("Time out for interest " + interest.getName());
upLoadData.isFinished = false;
//
if(timeOutNums.containsKey(upLoadData.sliceNum)){
int value = timeOutNums.get(upLoadData.sliceNum) + 1;
timeOutNums.put(upLoadData.sliceNum,value);
}else{
timeOutNums.put(upLoadData.sliceNum,1);
//
if (timeOutNums.containsKey(upLoadData.sliceNum)) {
int value = timeOutNums.get(upLoadData.sliceNum) + 1;
timeOutNums.put(upLoadData.sliceNum, value);
} else {
timeOutNums.put(upLoadData.sliceNum, 1);
}
}
}
}
@@ -376,18 +499,20 @@ public class UpLoadClientBasedFacePool {
@Override
public void onNetworkNack(Interest var1, NetworkNack var2){
congestionWindow.inFlightDecrease();
failedSlice.add(upLoadData.sliceNum* MainApp.sliceSize);
//
if(timeOutNums.containsKey(upLoadData.sliceNum)){
int value = timeOutNums.get(upLoadData.sliceNum) + 1;
timeOutNums.put(upLoadData.sliceNum,value);
}else{
timeOutNums.put(upLoadData.sliceNum,1);
if (!isClosed) {
congestionWindow.inFlightDecrease();
failedSlice.add(upLoadData.sliceNum * MainApp.sliceSize);
//
if (timeOutNums.containsKey(upLoadData.sliceNum)) {
int value = timeOutNums.get(upLoadData.sliceNum) + 1;
timeOutNums.put(upLoadData.sliceNum, value);
} else {
timeOutNums.put(upLoadData.sliceNum, 1);
}
callbackCount++;
System.out.println("onNetworkNack " + var1.getName());
upLoadData.isFinished = true;
}
callbackCount ++ ;
System.out.println("onNetworkNack " + var1.getName());
upLoadData.isFinished = true;
}
}
+50
View File
@@ -0,0 +1,50 @@
package cn.minoa.model;
// 断点续传中,需要持久化到本地的文件参数
public class BPRInfo {
// 文件唯一标识:上传中指的是哈希值,下载中指的是文件服务器URL
// 现在上传和下载的该数值全部定义为:纯文件名_文件长度
private String fileId;
// 文件名称
private String fileName;
// 文件位置:上传中指的是文件服务器位置,下载中指的是文件本地位置
private String fileLocator;
// 断点续传位置
private Long point;
public BPRInfo(){
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileLocator() {
return fileLocator;
}
public void setFileLocator(String fileLocator) {
this.fileLocator = fileLocator;
}
public Long getPoint() {
return point;
}
public void setPoint(Long point) {
this.point = point;
}
}
+37 -14
View File
@@ -1,22 +1,45 @@
package cn.minoa.util;
//import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class EncryptionUtil {
// 获取文件md5加密结果
// public static String getFileHash(String path){
// Long startTime = System.currentTimeMillis();
// // File
//// String path="E:\\系统镜像\\ubuntu-18.04.3-desktop-amd64.iso";
//// String path="E:\\系统镜像\\UltraISO.9.7.0.3476.exe";
// String res=null;
// try {
// res= DigestUtils.md5Hex(new FileInputStream(path));
// System.out.println("文件"+path+"加密结果:"+res);
// } catch (IOException e) {
// e.printStackTrace();
// }
// Long endTime=System.currentTimeMillis();
// System.out.println("文件"+path+"加密耗时:"+(endTime-startTime)+"ms");
// return res;
// }
public static String getMD5String(String str) {
str= URLEncoder.encode(str, StandardCharsets.UTF_8);
try {
// 生成一个MD5加密计算摘要
MessageDigest md = MessageDigest.getInstance("MD5");
// 计算md5函数
md.update(str.getBytes("utf-8"));
md.update(str.getBytes(StandardCharsets.UTF_8));
// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
//一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方)
@@ -30,6 +53,7 @@ public class EncryptionUtil {
}
public static String encryptBasedAES(String content) {
// content= URLEncoder.encode(content, StandardCharsets.UTF_8);
byte[] encrypt=encryptBasedAES(content,"123");
return ParseSystemUtil.parseByte2HexStr(encrypt);
}
@@ -46,18 +70,20 @@ public class EncryptionUtil {
* @return 密文
*/
public static byte[] encryptBasedAES(String content, String password) {
// content= URLEncoder.encode(content, StandardCharsets.UTF_8);
// password= URLEncoder.encode(password, StandardCharsets.UTF_8);
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
// kgen.init(128, new SecureRandom(password.getBytes()));// 利用用户密码作为随机数初始化出
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes("utf-8"));
secureRandom.setSeed(password.getBytes(StandardCharsets.UTF_8));
kgen.init(128, secureRandom);
//加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥,如果此密钥不支持编码,则返回
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
return result;
@@ -65,8 +91,6 @@ public class EncryptionUtil {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
@@ -78,13 +102,11 @@ public class EncryptionUtil {
}
public static String decryptBasedAES(String hexStr) {
// hexStr= URLEncoder.encode(hexStr, StandardCharsets.UTF_8);
byte[] byte2 = ParseSystemUtil.parseHexStr2Byte(hexStr);
try {
return new String(decryptBasedAES(byte2, "123"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
String s=new String(decryptBasedAES(byte2, "123"),StandardCharsets.UTF_8);
// s=URLEncoder.encode(s,StandardCharsets.UTF_8);
return s;
}
// public static byte[] decryptBasedAES(byte[] content) {
@@ -98,12 +120,13 @@ public class EncryptionUtil {
* @param password 加密时的密码
* @return 明文
*/
public static byte[] decryptBasedAES(byte[] content, String password) throws UnsupportedEncodingException {
public static byte[] decryptBasedAES(byte[] content, String password){
// password=URLEncoder.encode(password,StandardCharsets.UTF_8);
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
// kgen.init(128, new SecureRandom(password.getBytes()));
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes("utf-8"));
secureRandom.setSeed(password.getBytes(StandardCharsets.UTF_8));
kgen.init(128, secureRandom);
SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
@@ -0,0 +1,220 @@
package cn.minoa.util;
import cn.minoa.model.BPRInfo;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
// 文件断点续传支持类
// 功能:存储和移除传输失败的文件信息
public class FileBPRUtil {
// 判断某md5哈希值是否在本地存储条目中
public static boolean isHaveUploadBreakPointInfo(String hashString) {
// 加密
hashString= EncryptionUtil.encryptBasedAES(hashString);
InputStream inputStream = null;
try {
//如果 classPath 不存在,则获取的输入流会为 null
inputStream = new BufferedInputStream(new FileInputStream("." + File.separator + "ndn" + File.separator + "FileBPRenewal.properties"));
if (inputStream == null) {
System.out.println("没有找到断点续传配置文件...");
return false;
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(bf);
String filename=settingProperties.getProperty("fileName-"+hashString);
System.out.println(hashString+" : "+filename);
if(filename==null){
return false;
}else{
System.out.println("本地存在该文件的断点信息:"+hashString);
return true;
}
} catch (IOException e) {
// e.printStackTrace();
return false;
} finally {
//关闭输入流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// public static boolean isHaveDownloadBreakPointInfo(String fileUrlString) {
// return isHaveUploadBreakPointInfo(fileUrlString);
// }
// 存储上传文件断点信息到本地
public static void setUploadBreakPointInfo(String hashString,
String pureFileName,
String serverPath,
Long point){
// 加密
hashString= EncryptionUtil.encryptBasedAES(hashString);
pureFileName= EncryptionUtil.encryptBasedAES(pureFileName);
serverPath= EncryptionUtil.encryptBasedAES(serverPath);
String pointString= EncryptionUtil.encryptBasedAES(point.toString());
InputStream inputStream = null;
OutputStream outputStream=null;
try {
//如果 classPath 不存在,则获取的输入流会为 null
inputStream=new BufferedInputStream(new FileInputStream("."+ File.separator+"ndn"+File.separator+"FileBPRenewal.properties"));
if (inputStream == null) {
System.out.println("没有找到断点续传配置文件...");
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(bf);
settingProperties.setProperty("fileName-"+hashString, pureFileName);
settingProperties.setProperty("fileServerPath-"+hashString,serverPath);
settingProperties.setProperty("filePoint-"+hashString, pointString);
outputStream=new BufferedOutputStream(new FileOutputStream("."+ File.separator+"ndn"+File.separator+"FileBPRenewal.properties"));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream,StandardCharsets.UTF_8));
settingProperties.store(bw,"commit changes");
} catch (IOException e) {
e.printStackTrace();
}finally{
//关闭输入流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭输出流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 移除上传文件的断点信息
public static void deleteUploadBreakPointInfo(String hashString){
// 加密
hashString= EncryptionUtil.encryptBasedAES(hashString);
InputStream inputStream = null;
OutputStream outputStream=null;
try {
//如果 classPath 不存在,则获取的输入流会为 null
inputStream=new BufferedInputStream(new FileInputStream("."+ File.separator+"ndn"+File.separator+"FileBPRenewal.properties"));
if (inputStream == null) {
System.out.println("没有找到断点续传配置文件...");
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(bf);
settingProperties.remove("fileName-"+hashString);
settingProperties.remove("fileServerPath-"+hashString);
settingProperties.remove("filePoint-"+hashString);
outputStream=new BufferedOutputStream(new FileOutputStream("."+ File.separator+"ndn"+File.separator+"FileBPRenewal.properties"));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream,StandardCharsets.UTF_8));
settingProperties.store(bw,"commit changes");
} catch (IOException e) {
e.printStackTrace();
}finally{
//关闭输入流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭输出流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// public static void setDownloadBreakPointInfo(String fileUrlString,
// String pureFileName,
// String localPath,
// Long point){
// setUploadBreakPointInfo(fileUrlString,pureFileName,localPath,point);
// }
//
// public static void deleteDownloadBreakPointInfo(String fileUrlString){
// deleteUploadBreakPointInfo(fileUrlString);
// }
// 取出上传文件断点信息到本地
public static BPRInfo getUploadBreakPointInfo(String hashString) {
// 加密
hashString= EncryptionUtil.encryptBasedAES(hashString);
InputStream inputStream = null;
try {
//如果 classPath 不存在,则获取的输入流会为 null
inputStream = new BufferedInputStream(new FileInputStream("." + File.separator + "ndn" + File.separator + "FileBPRenewal.properties"));
if (inputStream == null) {
System.out.println("没有找到断点续传配置文件...");
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(bf);
BPRInfo bprInfo=new BPRInfo();
bprInfo.setFileId(hashString);
bprInfo.setFileName(EncryptionUtil.decryptBasedAES(settingProperties.getProperty("fileName-"+hashString)));
bprInfo.setFileLocator(EncryptionUtil.decryptBasedAES(settingProperties.getProperty("fileServerPath-"+hashString)));
bprInfo.setPoint(Long.parseLong(EncryptionUtil.decryptBasedAES(settingProperties.getProperty("filePoint-"+hashString))));
System.out.println("util-文件名:"+bprInfo.getFileName());
System.out.println("util-文件断点:"+bprInfo.getPoint());
System.out.println("util-文件路径:"+bprInfo.getFileLocator());
if((bprInfo.getFileName()==null)||(bprInfo.getPoint()==null)||(bprInfo.getFileLocator()==null)){
return null;
}
return bprInfo;
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭输入流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
// public static BPRInfo getDownloadBreakPointInfo(String fileUrlString) {
// return getUploadBreakPointInfo(fileUrlString);
// }
}
//1. 上传文件
// 1.1 如果上传成功,且该次上传是续传,则移除该文件哈希值对应的本地存储条目;
// 1.2 如果上传失败,则将文件断点信息存到本地:md5哈希值、纯文件名、服务器路径、断点
// 1.3 每次上传文件,都要计算一下md5哈希值,然后查表,看本地有没有这个哈希值。
// 如果有,就取文件名、要传的服务器路径,对比一下,全部都对的上,就从断点位置继续传该文件;如果没该哈希值,或文件名、路径不一致,则从0开始上传。
//
//2. 下载文件
// 2.1 如果下载成功,且该次下载是续传,则移除该次下载的文件对应的服务器url所对应的本地存储条目;
// 2.2 如果下载失败,则将文件断点信息保存到本地:文件对应的服务器url(如:/a/b.txt)、纯文件名、本地目录、断点
// 2.3 每次下载文件,都查看要下载的文件的服务器url是否在本地存储中。如果在,就取纯文件名、本地目录对比一下,如果全部都对的上,就从断点位置继续传该文件;如果没该服务器url,或文件名、路径不一致,则从0开始下载。
//3. 问题:
// 1. 由于上述断点全部存储在客户端,那么对于电脑突然死机或用户直接关闭客户端的情况,是无法将断点信息保存到本地的,也就无法续传;
// 2. 上述下载中,所谓文件服务器URL,并不是文件唯一标识,如果出现文件错判,续传之后的文件将可能是两个不同文件的结合体。
@@ -0,0 +1,144 @@
package cn.minoa.util;
// 生成配置文件
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
public class GenerateSettingFiles {
public static void generateInitFiles(){
generateNDNDir();
generateSettingFile();
generateBPRFile();
generateNDNBlockFile();
}
public static void generateNDNDir(){
String path="." + File.separator + "ndn";
File file=new File(path);
if(!file.exists()&&!file.isDirectory()){
file.mkdir();
System.out.println("ndn目录创建成功");
}else{
System.out.println("ndn目录已经存在");
}
}
public static void generateNDNBlockFile() {
String path = "." + File.separator + "ndn" + File.separator +"BlockSuccessUsers.properties";
generateNDNBlockFile(path);
}
public static void generateNDNBlockFile(String path) {
File file = new File(path);
// 创建配置文件
if (!file.exists()) {
try {
file.createNewFile();
System.out.println("区块链注册信息文件创建成功");
} catch (IOException e) {
System.out.println("区块链注册信息文件创建失败:" + e.getMessage());
}
} else {
System.out.println(path + "区块链注册信息文件已经存在");
}
}
public static void generateBPRFile() {
String path = "." + File.separator + "ndn" + File.separator +"FileBPRenewal.properties";
generateBPRFiles(path);
}
public static void generateBPRFiles(String path) {
File file = new File(path);
// 创建配置文件
if (!file.exists()) {
try {
file.createNewFile();
System.out.println("断点信息记录文件创建成功");
} catch (IOException e) {
System.out.println("断点信息记录文件创建失败:" + e.getMessage());
}
} else {
System.out.println(path + "断点信息记录文件已经存在");
}
}
public static void generateSettingFile() {
String path = "." + File.separator + "ndn" + File.separator + "settings.properties";
generateSettingFile(path);
}
public static void generateSettingFile(String path) {
File file = new File(path);
boolean isNew=false; //标志配置文件是否是新建的
// 创建配置文件
if (!file.exists()) {
isNew=true;
try {
file.createNewFile();
System.out.println("setting配置文件创建成功");
} catch (IOException e) {
System.out.println("setting配置文件创建失败:" + e.getMessage());
}
} else {
isNew=false;
System.out.println(path + "配置文件已经存在");
}
// 如果是新建配置文件,则写入配置文件的默认内容
if(isNew) {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
//如果 classPath 不存在,则获取的输入流会为 null
inputStream = new BufferedInputStream(new FileInputStream(path));
if (inputStream == null) {
System.out.println("没有找到配置文件...");
}
// 解决中文乱码问题
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(bf);
settingProperties.setProperty("ServerIPAddress", "116.77.74.139");
settingProperties.setProperty("ServerPortAddress", "6363");
settingProperties.setProperty("ndnBlockChainIPAddress", "116.77.74.139");
settingProperties.setProperty("ndnBlockChainPortAddress", "9001");
settingProperties.setProperty("DataPackagePrefix", "/ndn/edu/pkusz/OA");
settingProperties.setProperty("ThreadNumberForFileTransfer", "5");
settingProperties.setProperty("KeyName", "/default");
settingProperties.setProperty("LoginStatus", "false");
settingProperties.setProperty("loginUserName", "default");
settingProperties.setProperty("loginPassWord", "default");
outputStream = new BufferedOutputStream(new FileOutputStream(path));
// 解决中文乱码问题
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
settingProperties.store(bw, "初始化配置文件");
System.out.println("setting配置文件内容初始化成功");
} catch (IOException e) {
// e.printStackTrace();
System.out.println("setting配置文件内容填充失败" + e.getMessage());
} finally {
//关闭输入流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭输出流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}else{
System.out.println(path+"配置文件内容保持不变");
}
}
}
@@ -3,6 +3,7 @@ package cn.minoa.util;
import cn.minoa.MainApp;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
public class KeyStorageUtil {
@@ -17,11 +18,13 @@ public class KeyStorageUtil {
if (inputStream == null) {
System.out.println("没有找到配置文件...");
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(inputStream);
settingProperties.load(bf);
settingProperties.setProperty("KeyName", keyName);
outputStream=new BufferedOutputStream(new FileOutputStream(MainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties"));
settingProperties.store(outputStream,"修改配置文件");
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream,StandardCharsets.UTF_8));
settingProperties.store(bw,"修改配置文件");
} catch (IOException e) {
e.printStackTrace();
}finally{
@@ -49,13 +52,15 @@ public class KeyStorageUtil {
InputStream inputStream = null;
try {
//如果 classPath 不存在,则获取的输入流会为 null
inputStream = new BufferedInputStream(new FileInputStream(MainApp.getClientPath() + File.separator + "ndn" + File.separator + "settings.properties"));
inputStream = new BufferedInputStream(new FileInputStream("." + File.separator + "ndn" + File.separator +
"settings.properties"));
// inputStream = MainApp.class.getClassLoader().getResourceAsStream("/ndn/settings.properties");
if (inputStream == null) {
System.out.println("没有找到配置文件...");
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(inputStream);
settingProperties.load(bf);
String keyName = settingProperties.getProperty("KeyName");
return keyName;
} catch (IOException e) {
+2 -1
View File
@@ -9,7 +9,8 @@ public class LoggerUtil {
// 将文件名、文件操作、传输耗时等信息写入日志.
public static void insertFileAction(String filename, String fileaction, String usedtime) {
try {
File file = new File("./ndn/log.txt");
File file = new File("." + File.separator + "ndn" +
File.separator +"log.txt");
FileOutputStream fos = null;
if (!file.exists()) {
file.createNewFile();//如果文件不存在,就创建该文件
@@ -0,0 +1,116 @@
package cn.minoa.util;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
public class RegisterUtil {
// 用户记录:通过了区块链注册,但是没有通过后台注册的用户前缀
public static boolean isAccessedBlockUser(String prefix) {
// 加密
String hashString= EncryptionUtil.encryptBasedAES(prefix);
InputStream inputStream = null;
try {
//如果 classPath 不存在,则获取的输入流会为 null
inputStream = new BufferedInputStream(new FileInputStream("." + File.separator + "ndn" + File.separator + "BlockSuccessUsers.properties"));
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(bf);
String filename=settingProperties.getProperty(hashString);
System.out.println(hashString+" : "+filename);
if(filename==null){
return false;
}else{
System.out.println("本地存在该文件的断点信息:"+hashString);
return true;
}
} catch (IOException e) {
// e.printStackTrace();
return false;
} finally {
//关闭输入流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void setAccessedBlockUser(String prefix){
// 加密
String hashString= EncryptionUtil.encryptBasedAES(prefix);
InputStream inputStream = null;
OutputStream outputStream=null;
try {
//如果 classPath 不存在,则获取的输入流会为 null
inputStream=new BufferedInputStream(new FileInputStream("."+ File.separator+"ndn"+File.separator+"BlockSuccessUsers.properties"));
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(bf);
settingProperties.setProperty(hashString, hashString);
outputStream=new BufferedOutputStream(new FileOutputStream("."+ File.separator+"ndn"+File.separator+"BlockSuccessUsers.properties"));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream,StandardCharsets.UTF_8));
settingProperties.store(bw,"commit changes: add a prefix");
} catch (IOException e) {
e.printStackTrace();
}finally{
//关闭输入流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭输出流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void deleteAccessedBlockUser(String prefix){
// 加密
String hashString= EncryptionUtil.encryptBasedAES(prefix);
InputStream inputStream = null;
OutputStream outputStream=null;
try {
//如果 classPath 不存在,则获取的输入流会为 null
inputStream=new BufferedInputStream(new FileInputStream("."+ File.separator+"ndn"+File.separator+"BlockSuccessUsers.properties"));
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(bf);
settingProperties.remove(hashString);
outputStream=new BufferedOutputStream(new FileOutputStream("."+ File.separator+"ndn"+File.separator+"BlockSuccessUsers.properties"));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream,StandardCharsets.UTF_8));
settingProperties.store(bw,"commit changes: delete a prefix");
} catch (IOException e) {
e.printStackTrace();
}finally{
//关闭输入流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭输出流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
@@ -1,10 +1,9 @@
package cn.minoa.view.home;
import cn.minoa.MainApp;
import cn.minoa.dataRequestInterface.DownLoadClientBasedFacePool;
import cn.minoa.dataRequestInterface.DownLoadClientBPRenewal;
import cn.minoa.dataRequestInterface.OrderInfo;
import cn.minoa.dataRequestInterface.ResponseData;
import cn.minoa.model.Email;
import cn.minoa.model.Reimbursement;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
@@ -14,14 +13,11 @@ import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
public class DealSingleReimbursementController {
private MainApp mainApp;
@@ -126,7 +122,7 @@ public class DealSingleReimbursementController {
sliceNum++;
}
Long startTime = System.currentTimeMillis();
DownLoadClientBasedFacePool downLoadClient = new DownLoadClientBasedFacePool(pathfilename,
DownLoadClientBPRenewal downLoadClient = new DownLoadClientBPRenewal(pathfilename,
localDirString,sliceNum,mainApp.threadNumberForFileTransfer);
// 下载文件
boolean res = downLoadClient.downloadData();
@@ -1,9 +1,8 @@
package cn.minoa.view.home;
import cn.minoa.MainApp;
import cn.minoa.dataRequestInterface.DownLoadClientBasedFacePool;
import cn.minoa.dataRequestInterface.DownLoadClientBPRenewal;
import cn.minoa.model.Reimbursement;
import cn.minoa.view.login.LoginOverviewController;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.ListView;
@@ -115,7 +114,7 @@ public class SingleReimbursementDetailsController {
sliceNum++;
}
Long startTime = System.currentTimeMillis();
DownLoadClientBasedFacePool downLoadClient = new DownLoadClientBasedFacePool(pathfilename,
DownLoadClientBPRenewal downLoadClient = new DownLoadClientBPRenewal(pathfilename,
localDirString,sliceNum,mainApp.threadNumberForFileTransfer);
// 下载文件
boolean res = downLoadClient.downloadData();
@@ -1,10 +1,12 @@
package cn.minoa.view.login;
import cn.minoa.Main;
import cn.minoa.MainApp;
import cn.minoa.model.Loginer;
import cn.minoa.util.EncryptionUtil;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
// 维持长登录状态
@@ -19,15 +21,17 @@ public class KeepLoginStatus {
if (inputStream == null) {
System.out.println("没有找到配置文件...");
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(inputStream);
settingProperties.load(bf);
if(flag==true){
settingProperties.setProperty("LoginStatus","true");
}else{
settingProperties.setProperty("LoginStatus","false");
}
outputStream=new BufferedOutputStream(new FileOutputStream(MainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties"));
settingProperties.store(outputStream,"修改配置文件");
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream,StandardCharsets.UTF_8));
settingProperties.store(bw,"修改配置文件");
} catch (IOException e) {
e.printStackTrace();
}finally{
@@ -59,12 +63,14 @@ public class KeepLoginStatus {
if (inputStream == null) {
System.out.println("没有找到配置文件...");
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(inputStream);
settingProperties.setProperty("loginUserName", EncryptionUtil.encryptBasedAES(loginer.getUserName()));
settingProperties.setProperty("loginPassWord", EncryptionUtil.encryptBasedAES(loginer.getPassWord()));
settingProperties.load(bf);
settingProperties.setProperty("loginUserName",EncryptionUtil.encryptBasedAES(loginer.getUserName()));
settingProperties.setProperty("loginPassWord",EncryptionUtil.encryptBasedAES(loginer.getPassWord()));
outputStream=new BufferedOutputStream(new FileOutputStream(MainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties"));
settingProperties.store(outputStream,"修改配置文件");
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream,StandardCharsets.UTF_8));
settingProperties.store(bw,"修改配置文件");
} catch (IOException e) {
e.printStackTrace();
}finally{
@@ -97,8 +103,9 @@ public class KeepLoginStatus {
if (inputStream == null) {
System.out.println("没有找到配置文件...");
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(inputStream);
settingProperties.load(bf);
String username = EncryptionUtil.decryptBasedAES(settingProperties.getProperty("loginUserName"));
String password = EncryptionUtil.decryptBasedAES(settingProperties.getProperty("loginPassWord"));
// System.out.println("username: " + username);
@@ -129,8 +136,9 @@ public class KeepLoginStatus {
if (inputStream == null) {
System.out.println("没有找到配置文件...");
}
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(inputStream);
settingProperties.load(bf);
String LoginStatus = settingProperties.getProperty("LoginStatus");
if(LoginStatus.equals("true")){
return true;
@@ -453,7 +453,7 @@ public class LoginOverviewController {
// 获取用户列表信息
ResponseData responseData = mainApp.minoaDataAPI.dataCacheQueue.getResponseDataBySeq(seqLong);
JSONObject jsonObject = responseData.praseRequestData();
// System.out.println("getUsers-JSON: "+jsonObject.toString());
System.out.println("getUsers-JSON: "+jsonObject.toString());
Integer codeInteger = null;
try {
codeInteger = jsonObject.getInt("code");
@@ -1004,7 +1004,7 @@ public class LoginOverviewController {
sliceNum++;
}
Long startTime = System.currentTimeMillis();
DownLoadClientBasedFacePool downLoadClient = new DownLoadClientBasedFacePool(filename,
DownLoadClientBPRenewal downLoadClient = new DownLoadClientBPRenewal(filename,
localDir,sliceNum,mainApp.threadNumberForFileTransfer);
// 下载文件
boolean res = downLoadClient.downloadData();
@@ -2,11 +2,27 @@ package cn.minoa.view.login;
// 与区块链建立TCP连接,发送注册请求
import cn.minoa.MainApp;
import cn.minoa.dataRequestInterface.KeyManager;
import net.named_data.jndn.Name;
import net.named_data.jndn.Signature;
import net.named_data.jndn.encoding.der.DerDecodingException;
import net.named_data.jndn.security.KeyChain;
import net.named_data.jndn.security.SecurityException;
import net.named_data.jndn.security.SigningInfo;
import net.named_data.jndn.security.pib.PibImpl;
import net.named_data.jndn.security.tpm.TpmBackEnd;
import net.named_data.jndn.security.v2.CertificateV2;
import net.named_data.jndn.util.Blob;
import net.named_data.jndn.util.Common;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.*;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.security.cert.Certificate;
public class NDNBlockChainConnectClient {
@@ -14,20 +30,77 @@ public class NDNBlockChainConnectClient {
private Integer NDNBlockChainPortAddress;
public NDNBlockChainConnectClient(){
// this.NDNBlockChainIPAddress="116.77.74.144";
// this.NDNBlockChainIPAddress="121.15.171.86";
// this.NDNBlockChainPortAddress=8010;
this.NDNBlockChainIPAddress= MainApp.NDNBlockChainIPAddress;
System.out.println("区块链IP:"+ MainApp.NDNBlockChainIPAddress);
this.NDNBlockChainPortAddress= MainApp.NDNBlockChainPortAddress;
System.out.println("区块链Port:"+ MainApp.NDNBlockChainPortAddress);
System.out.println("区块链IP:"+MainApp.NDNBlockChainIPAddress);
this.NDNBlockChainPortAddress=MainApp.NDNBlockChainPortAddress;
System.out.println("区块链Port:"+MainApp.NDNBlockChainPortAddress);
}
public NDNBlockChainConnectClient(String ipAddress, Integer portAddress){
public NDNBlockChainConnectClient(String ipAddress,Integer portAddress){
this.NDNBlockChainIPAddress= ipAddress;
this.NDNBlockChainPortAddress=portAddress;
}
// 将已在区块链后台注册成功的用户注销掉
public String deleteUser(String username,String sig){
String prefix="/"+username;
// 获取注册数组
byte[] registerByte=getBlockChainDeleteBuffer(prefix,sig);
System.out.println("delete length: "+registerByte.length);
// 通过TCP连接区块链后台
Socket blockchainClient;
try {
blockchainClient=new Socket(NDNBlockChainIPAddress,NDNBlockChainPortAddress);
} catch (IOException e) {
e.printStackTrace();
System.out.println("连接不可达:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress);
return e.getMessage();
}
System.out.println("已成功建立TCP连接:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress
+"; 远程主机地址:"+blockchainClient.getRemoteSocketAddress());
try {
OutputStream outToServer = blockchainClient.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.write(registerByte);
InputStream inFromServer = blockchainClient.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
System.out.println("正在等待服务器响应...");
byte[] res = new byte[4];
in.read(res);
int resSize = Bytes2Int_LE(res);
System.out.println("返回值长度为:"+ resSize);
res = new byte[resSize];
in.read(res);
System.out.println("返回值内容为:" + new String(res, StandardCharsets.UTF_8));
System.out.println("服务器响应: " );
blockchainClient.close();
System.out.println("已关闭此次TCP连接:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress);
// System.out.println("服务器响应: " );
// 解析返回来的数据,如果是200,就返回true
try {
String resString=new String(res,StandardCharsets.UTF_8);
System.out.println("resString: "+resString);
JSONObject resObject=new JSONObject(resString);
int resCode=resObject.getInt("StatusCode");
String message=resObject.getString("Message");
if(resCode==200){
System.out.println("区块链销户成功:"+username);
return "true";
}else{
return message;
}
} catch (JSONException e) {
e.printStackTrace();
return e.getMessage();
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("销户时数据交换出错:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress);
return e.getMessage();
}
}
// 添加白名单
public String addWhiteUser(String phone){
// 获取注册数组
@@ -117,14 +190,14 @@ public class NDNBlockChainConnectClient {
System.out.println("返回值长度为:"+ resSize);
res = new byte[resSize];
in.read(res);
System.out.println("返回值内容为:" + new String(res));
System.out.println("返回值内容为:" + new String(res, StandardCharsets.UTF_8));
System.out.println("服务器响应: " );
blockchainClient.close();
System.out.println("已关闭此次TCP连接:"+NDNBlockChainIPAddress+":"+NDNBlockChainPortAddress);
// System.out.println("服务器响应: " );
// 解析返回来的数据,如果是200,就返回true
try {
String resString=new String(res);
String resString=new String(res,StandardCharsets.UTF_8);
System.out.println("resString: "+resString);
JSONObject resObject=new JSONObject(resString);
int resCode=resObject.getInt("StatusCode");
@@ -150,19 +223,15 @@ public class NDNBlockChainConnectClient {
private byte[] getBlockChainRegisterBuffer(String username,String phone, String pubkey) {
String registerString=getBlockChainRegisterJsonString(username,phone, pubkey);
System.out.println("json: "+registerString);
int jsonLen = registerString.getBytes().length;
int jsonLen = registerString.getBytes(StandardCharsets.UTF_8).length;
System.out.println("json len: "+jsonLen);
byte[] registerByte=new byte[jsonLen+4];
// System.arraycopy(intToBytesLittle(jsonLen),0,
// registerByte,0,4);
System.arraycopy(intToBytesLittle(jsonLen),0,
registerByte,0,4);
try {
System.arraycopy(registerString.getBytes("utf-8"),
0,registerByte,4,jsonLen);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.arraycopy(registerString.getBytes(StandardCharsets.UTF_8),
0,registerByte,4,jsonLen);
return registerByte;
}
@@ -172,16 +241,23 @@ public class NDNBlockChainConnectClient {
int jsonLen = registerString.getBytes().length;
System.out.println("json len: "+jsonLen);
byte[] registerByte=new byte[jsonLen+4];
// System.arraycopy(intToBytesLittle(jsonLen),0,
// registerByte,0,4);
System.arraycopy(intToBytesLittle(jsonLen),0,
registerByte,0,4);
try {
System.arraycopy(registerString.getBytes("utf-8"),
0,registerByte,4,jsonLen);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.arraycopy(registerString.getBytes(StandardCharsets.UTF_8),
0,registerByte,4,jsonLen);
return registerByte;
}
private byte[] getBlockChainDeleteBuffer(String prefix,String sig) {
String registerString=getBlockChainDeleteUserJsonString(prefix,sig);
System.out.println("json: "+registerString);
int jsonLen = registerString.getBytes().length;
System.out.println("json len: "+jsonLen);
byte[] registerByte=new byte[jsonLen+4];
System.arraycopy(intToBytesLittle(jsonLen),0,
registerByte,0,4);
System.arraycopy(registerString.getBytes(StandardCharsets.UTF_8),
0,registerByte,4,jsonLen);
return registerByte;
}
@@ -231,7 +307,49 @@ public class NDNBlockChainConnectClient {
return iRst;
}
// 从前端界面获得登录数据并转换成json格式
private String getBlockChainDeleteUserJsonString(String prefix,String sig) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("Type", "user-act");
jsonObject.put("Command", "Destroy");
jsonObject.put("Prefix",prefix);
jsonObject.put("Timestamp","");
jsonObject.put("Sig",sig);
} catch (Exception e) {
System.out.println("exception: " + e.getMessage());
}
return jsonObject.toString();
}
public static String signBuf(String prefix, CertificateV2 certificateV2){
// 构建msg
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("Type", "user-act");
jsonObject.put("Command", "Destroy");
jsonObject.put("Prefix",prefix);
jsonObject.put("Timestamp","");
} catch (Exception e) {
System.out.println("exception: " + e.getMessage());
}
String msg=jsonObject.toString();
ByteBuffer byteBuffer=ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8));// 这句是C++没有的
try {
SigningInfo signingInfo = new SigningInfo();
signingInfo.setSigningIdentity(certificateV2.getIdentity());
Blob blob= KeyManager.INSTANCE.getKeyChain().sign(byteBuffer,signingInfo);
// String sig=blob.toHex();
String sig=Common.base64Encode(blob.getImmutableArray(), false);
// String sig= Common.base64Encode(signature.getSignature().getImmutableArray());
// String sig1=signature.getSignature().toHex();
System.out.println("sig: "+sig);
return sig;
} catch (PibImpl.Error | KeyChain.Error | TpmBackEnd.Error e) {
e.printStackTrace();
return "";
}
}
private String getBlockChainWhiteUserJsonString(String phone) {
JSONObject jsonObject = new JSONObject();
String typeString = "whiteUser";
@@ -7,6 +7,7 @@ import cn.minoa.dataRequestInterface.OrderInfo;
import cn.minoa.dataRequestInterface.ResponseData;
import cn.minoa.util.EncryptionUtil;
import cn.minoa.util.KeyStorageUtil;
import cn.minoa.util.RegisterUtil;
import cn.minoa.util.StringByteLengthUtil;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
@@ -15,7 +16,12 @@ import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import net.named_data.jndn.Interest;
import net.named_data.jndn.Name;
import net.named_data.jndn.Signature;
import net.named_data.jndn.security.KeyChain;
import net.named_data.jndn.security.SecurityException;
import net.named_data.jndn.security.SigningInfo;
import net.named_data.jndn.security.pib.Pib;
import net.named_data.jndn.security.pib.PibImpl;
import net.named_data.jndn.security.tpm.Tpm;
@@ -26,6 +32,8 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.nio.ByteBuffer;
public class RegisterOverviewController {
@SuppressWarnings("unused")
@@ -72,7 +80,7 @@ public class RegisterOverviewController {
Long seqLong = mainApp.getNewDataReqId();
orderInfo.setSeq(seqLong);
// 生成本地pid.db文件,获取公钥
String publicKey="";
String publicKey ;
try {
CertificateV2 certificateV2= KeyManager.INSTANCE.initKeyChain(keyChainNameString).getCertification(keyChainNameString);
publicKey = Common.base64Encode(certificateV2.wireEncode().getImmutableArray(), false);
@@ -85,28 +93,41 @@ public class RegisterOverviewController {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("注册失败");
alert.setHeaderText("注册账号失败");
alert.setContentText("本地密钥生成失败:\n"+error.getMessage());
alert.setContentText("本地密钥生成失败:\n"+error.getMessage()+"\n"
+"建议更换用户名,重新进行注册!");
alert.showAndWait();
return ;
}
// 首先向区块链发送注册信息
String pubkey=publicKey;
// String pubkey = "Bv0CIgcvCAVsbGFhYQgDS0VZCAhyVwiW+kaX7QgMY2VydC1yZXF1ZXN0CAn9AAABcSP8KDIUCRgBAhkEAiVRABX9AU8wggFLMIIBAwYHKoZIzj0CATCB9wIBATAsBgcqhkjOPQEBAiEA/////wAAAAEAAAAAAAAAAAAAAAD///////////////8wWwQg/////wAAAAEAAAAAAAAAAAAAAAD///////////////wEIFrGNdiqOpPns+u9VXaYhrxlHQawzFOw9jvOPD4n0mBLAxUAxJ02CIbnBJNqZnjhE50mt4GffpAEQQRrF9Hy4SxCR/i85uVjpEDydwN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQEDQgAEgCbgPaAk0RRziBAW/beuF5fBQdJdbZhtKrT+FRdXq6sqPxvhM3VQF+WrBehiA5TsKpLzwzNoE8kKt8gyevM4dxZHGwEDHBgHFggFbGxhYWEIA0tFWQgIclcIlvpGl+39AP0m/QD+DzIwMjAwMzI5VDAxNTEwMf0A/w8yMDIwMDQwOFQwMTUxMDAXSDBGAiEApxH8lJntSBM/NwV+laSdifH674+76xZnxVF4vKGaXXkCIQCj3OyzagvjqYrJmZ9f00PWVISXRyrIrKmwFbwzsk/hQw==";
String phonenumber=phoneNumber.getText().trim();
NDNBlockChainConnectClient ndnBlockChainConnectClient=new NDNBlockChainConnectClient();
String resString=ndnBlockChainConnectClient.registeNewUser(username,
phonenumber,pubkey);
if(resString.equals("true")){
System.out.println("用户【"+username+"】在区块链后台被成功注册");
}else{
System.out.println("区块链后台注册用户【"+username+"】失败: "+resString);
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("区块链注册失败");
alert.setHeaderText("区块链注册失败");
alert.setContentText("失败原因:\n"+resString);
alert.showAndWait();
return ;
// 标志该用户是否已经通过了区块链注册
boolean b_flag=RegisterUtil.isAccessedBlockUser(keyChainNameString);
// 如果没有注册成功过,向区块链发送注册信息;否则,跳过区块链注册
if(!b_flag) {
String pubkey = publicKey;
String phonenumber = phoneNumber.getText().trim();
NDNBlockChainConnectClient ndnBlockChainConnectClient = new NDNBlockChainConnectClient();
String resString = ndnBlockChainConnectClient.registeNewUser(username,
phonenumber, pubkey);
if (resString.equals("true")) {
System.out.println("用户【" + username + "】在区块链后台被成功注册");
} else {
// 区块链没有注册用户成功,则删掉刚刚生成的密钥文件
try {
KeyManager.INSTANCE.getKeyChain().deleteIdentity(new Name(keyChainNameString));
System.out.println("已删除本地密钥:"+keyChainNameString);
} catch (SecurityException e) {
e.printStackTrace();
}
System.out.println("区块链后台注册用户【" + username + "】失败: " + resString);
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("区块链注册失败");
alert.setHeaderText("区块链注册失败");
alert.setContentText("失败原因:\n" + resString+"\n"
+"请确保你输入的手机号在系统白名单中,且用户名并没有被注册过。\n " +
"您可以将用户名适当复杂化,以保证其在系统中的唯一性。");
alert.showAndWait();
return;
}
}
// 获取注册时JSON
String registerJson=getRegisterJson(publicKey);
@@ -127,7 +148,11 @@ public class RegisterOverviewController {
}
if (codeInteger == 200) {
// 注册之后,使用getNews消耗掉新通知
makeNoticesBeRead();
// makeNoticesBeRead();
// 如果该用户是原来注册中断的用户,移除其本地信息
if(b_flag) {
RegisterUtil.deleteAccessedBlockUser(keyChainNameString);
}
// 将此时的keyChainName持久化到本地
MinoaDataAPI.keyChainNameString=keyChainNameString;
KeyStorageUtil.setKeyName(keyChainNameString);
@@ -139,11 +164,20 @@ public class RegisterOverviewController {
alert.showAndWait();
dialogStage.close();
} else {
// 后台没有注册用户成功,则删掉刚刚生成的密钥文件
try {
KeyManager.INSTANCE.getKeyChain().deleteIdentity(new Name(keyChainNameString));
System.out.println("已删除本地密钥:"+keyChainNameString);
} catch (SecurityException e) {
e.printStackTrace();
}
// 将该用户(区块链注册成功,后台注册失败)的注册前缀,保存到本地
RegisterUtil.setAccessedBlockUser(keyChainNameString);
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("注册失败");
alert.setHeaderText("注册失败");
alert.setContentText("请确保你输入的手机号在系统白名单中,且登录名/账户/昵称并没有被注册过。\n " +
alert.setContentText("请确保你输入的手机号在系统白名单中,且用户名并没有被注册过。\n " +
"您可以将用户名适当复杂化,以保证其在系统中的唯一性。");
alert.showAndWait();
}
@@ -321,12 +355,13 @@ public class RegisterOverviewController {
// 验证输入内容格式
private boolean isRightContent() {
//验证昵称是否为空
if (nickname.getText().trim().equals("")||nickname.getText().trim().contains("@")) {
if (nickname.getText().trim().equals("")||nickname.getText().trim().contains("@")||nickname.getText().trim().contains(" ")) {
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("账号错误");
alert.setHeaderText("你的账号错误");
alert.setContentText("请确保你输入的账号(昵称)不为空,且昵称中不包含\"@\"字符");
alert.setContentText("请确保你输入的账号(昵称)不为空,且昵称中不包含\"@\"字符;\n" +
"此外,请确保输入的昵称中不包含空格");
alert.showAndWait();
return false;
}
@@ -12,6 +12,7 @@ import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
//import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import java.util.regex.Pattern;
@@ -28,6 +29,12 @@ public class SettingOverviewController {
@FXML
private TextField packetPrefix;
@FXML
private TextField fileThread;
@FXML
private TextField BlockIP;
@FXML
private TextField BlockPort;
@FXML
private ImageView miniLogo;
public SettingOverviewController(){
@@ -40,6 +47,9 @@ public class SettingOverviewController {
ipAddress.setPromptText("IP格式示例:121.15.171.89");
portAddress.setPromptText("端口号格式示例:6363");
packetPrefix.setPromptText("格式示例:/ndn/edu/pkusz/OA)");
fileThread.setPromptText("文件传输并发数[1-100]");
BlockIP.setPromptText("IP格式示例:121.15.171.89");
BlockPort.setPromptText("端口号格式示例:8010");
}
// 根据表单修改配置文件
@@ -49,12 +59,13 @@ public class SettingOverviewController {
//修改本地配置文件
changeSettingProperties();
mainApp.loadSettingProperties();
reloadSetting();
//弹窗提示
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("设置成功");
alert.setHeaderText("服务器地址/包前缀修改成功");
alert.setContentText("您已成功修改服务器IP/包前缀。\n请重新启动应用以生效新设置!");
alert.setHeaderText("配置文件修改成功");
alert.setContentText("您已成功修改系统配置。\n请重新启动应用以生效新设置!");
alert.showAndWait();
System.exit(0);
}
@@ -70,16 +81,23 @@ public class SettingOverviewController {
if (inputStream == null) {
System.out.println("没有找到配置文件...");
}
// 解决中文乱码问题
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
Properties settingProperties = new Properties();
settingProperties.load(inputStream);
settingProperties.load(bf);
settingProperties.setProperty("ServerIPAddress",ipAddress.getText().trim());
settingProperties.setProperty("ServerPortAddress",portAddress.getText().trim());
settingProperties.setProperty("DataPackagePrefix",packetPrefix.getText().trim());
settingProperties.setProperty("ThreadNumberForFileTransfer",fileThread.getText().trim());
settingProperties.setProperty("ndnBlockChainIPAddress",BlockIP.getText().trim());
settingProperties.setProperty("ndnBlockChainPortAddress",BlockPort.getText().trim());
outputStream=new BufferedOutputStream(new FileOutputStream(mainApp.getClientPath()+ File.separator+"ndn"+File.separator+"settings.properties"));
// 解决中文乱码问题
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
// URL url = MainApp.class.getClassLoader().getResource("ndn/settings.properties");
// outputStream = new FileOutputStream(url.getPath());
settingProperties.store(outputStream,"修改配置文件");
settingProperties.store(bw,"修改配置文件");
} catch (IOException e) {
e.printStackTrace();
}finally{
@@ -102,6 +120,15 @@ public class SettingOverviewController {
}
}
// 重载参数
private void reloadSetting(){
ipAddress.setText(mainApp.minoaServerIpString);
portAddress.setText(mainApp.minoaServerPortInteger.toString());
fileThread.setText(mainApp.threadNumberForFileTransfer.toString());
packetPrefix.setText(mainApp.globalPrefixString);
packetPrefix.setDisable(true);
}
/*
* @param mainApp
*/
@@ -109,8 +136,11 @@ public class SettingOverviewController {
this.mainApp = mainApp;
ipAddress.setText(mainApp.minoaServerIpString);
portAddress.setText(mainApp.minoaServerPortInteger.toString());
fileThread.setText(mainApp.threadNumberForFileTransfer.toString());
packetPrefix.setText(mainApp.globalPrefixString);
packetPrefix.setDisable(true);
BlockIP.setText(mainApp.NDNBlockChainIPAddress);
BlockPort.setText(mainApp.NDNBlockChainPortAddress.toString());
}
/*
@@ -192,6 +222,36 @@ public class SettingOverviewController {
alert.showAndWait();
return false;
}
//验证前缀是否为空
if (fileThread.getText().trim().equals("")) {
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("线程数错误");
alert.setHeaderText("你的线程数错误");
alert.setContentText("请确保你输入的线程数不为空。");
alert.showAndWait();
return false;
}
//判断线程数是否正确
boolean flag_thread=true;
try{
Integer threadnumber=Integer.parseInt(fileThread.getText().trim());
if((threadnumber<1)||(threadnumber>100)){
flag_thread=false;
}
}catch(Exception e){
flag_thread=false;
}finally {
if(flag_thread==false){
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("线程数错误");
alert.setHeaderText("你的线程数错误");
alert.setContentText("请确保你输入的文件传输线程数是正整数且范围在1-100之间。");
alert.showAndWait();
return false;
}
}
//使用socket判断这里的ip和端口号是否可以连接上
String ipHost=ipAddress.getText().trim();
Integer portHost=Integer.parseInt(portAddress.getText().trim());
@@ -204,6 +264,68 @@ public class SettingOverviewController {
alert.showAndWait();
return false;
}
//验证IP是否为空
if (BlockIP.getText().trim().equals("")) {
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("IP错误");
alert.setHeaderText("你的区块链IP错误");
alert.setContentText("请确保你输入的区块链IP不为空。");
alert.showAndWait();
return false;
}
//验证IP格式是否正确
if (!ipCheck(BlockIP.getText().trim())) {
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("IP错误");
alert.setHeaderText("你的区块链IP错误");
alert.setContentText("请确保你输入的区块链IP格式正确。");
alert.showAndWait();
return false;
}
//验证端口号是否为空
if (BlockPort.getText().trim().equals("")) {
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("端口号错误");
alert.setHeaderText("你的区块链端口号错误");
alert.setContentText("请确保你输入的区块链端口号不为空。");
alert.showAndWait();
return false;
}
//判断端口号是否正确
boolean flag_b_port=true;
try{
Integer port=Integer.parseInt(BlockPort.getText().trim());
if((port<1)||(port>65535)){
flag_b_port=false;
}
}catch(Exception e){
flag_b_port=false;
}finally {
if(flag_b_port==false){
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("端口号错误");
alert.setHeaderText("你的区块链端口号错误");
alert.setContentText("请确保你输入的区块链端口号格式正确。");
alert.showAndWait();
return false;
}
}
//使用socket判断这里的ip和端口号是否可以连接上
ipHost=BlockIP.getText().trim();
portHost=Integer.parseInt(BlockPort.getText().trim());
if(!isHostConnectable(ipHost,portHost)){
// 弹窗参考:https://code.makery.ch/blog/javafx-dialogs-official/
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("连接错误");
alert.setHeaderText("地址连接错误");
alert.setContentText("请确保你输入的区块链IP及端口号是可达的。");
alert.showAndWait();
return false;
}
//判断是否与原内容一致
if(isNotChange()){
Alert alert = new Alert(Alert.AlertType.WARNING);
@@ -219,8 +341,11 @@ public class SettingOverviewController {
// 判断新设置的参数是否与原参数一致
public boolean isNotChange(){
if(ipAddress.getText().trim().equals(mainApp.minoaServerIpString)&&
portAddress.getText().trim().equals(mainApp.minoaServerPortInteger.toString())&&
packetPrefix.getText().trim().equals(mainApp.globalPrefixString)){
portAddress.getText().trim().equals(mainApp.minoaServerPortInteger.toString())&&
packetPrefix.getText().trim().equals(mainApp.globalPrefixString)&&
fileThread.getText().trim().equals(mainApp.threadNumberForFileTransfer.toString())&&
BlockIP.getText().trim().equals(mainApp.NDNBlockChainIPAddress)&&
BlockPort.getText().trim().equals(mainApp.NDNBlockChainPortAddress.toString())){
return true;
}else{
return false;
@@ -3,7 +3,7 @@ package cn.minoa.view.mine;
import java.io.File;
import cn.minoa.MainApp;
import cn.minoa.dataRequestInterface.DownLoadClientBasedFacePool;
import cn.minoa.dataRequestInterface.DownLoadClientBPRenewal;
import cn.minoa.model.Email;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
@@ -14,7 +14,6 @@ import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class SingleEmailDetailsController {
@@ -132,7 +131,7 @@ public class SingleEmailDetailsController {
sliceNum++;
}
Long startTime = System.currentTimeMillis();
DownLoadClientBasedFacePool downLoadClient = new DownLoadClientBasedFacePool(pathfilename,
DownLoadClientBPRenewal downLoadClient = new DownLoadClientBPRenewal(pathfilename,
localDirString,sliceNum,mainApp.threadNumberForFileTransfer);
// 下载文件
boolean res = downLoadClient.downloadData();
@@ -8,37 +8,46 @@
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="325.0" prefWidth="425.0" stylesheets="@Register.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cn.minoa.view.login.SettingOverviewController">
<children>
<Button mnemonicParsing="false" opacity="0.0" text="避免聚焦" />
<AnchorPane fx:id="upSplite" opacity="0.45" prefHeight="80.0" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ImageView fx:id="miniLogo" fitHeight="35.0" fitWidth="35.0" layoutX="-50.0" layoutY="-47.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="2.0" AnchorPane.topAnchor="2.0" />
<Label layoutX="37.0" layoutY="12.0" prefHeight="35.0" text="minoa" AnchorPane.leftAnchor="40.0" AnchorPane.topAnchor="2.0">
<font>
<Font name="Arial Black" size="12.0" />
</font></Label>
</children>
</AnchorPane>
<GridPane layoutX="152.0" layoutY="110.0" AnchorPane.bottomAnchor="100.0" AnchorPane.leftAnchor="100.0" AnchorPane.rightAnchor="100.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="108.0" minWidth="10.0" prefWidth="57.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="172.0" minWidth="10.0" prefWidth="168.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<TextField fx:id="ipAddress" GridPane.columnIndex="1" />
<Label text="IP地址" />
<Label text="端口号" GridPane.rowIndex="1" />
<Label text="包前缀" GridPane.rowIndex="2" />
<TextField fx:id="packetPrefix" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<TextField fx:id="portAddress" GridPane.columnIndex="1" GridPane.rowIndex="1" />
</children>
</GridPane>
<Button layoutX="112.0" layoutY="263.0" mnemonicParsing="false" onAction="#handleSetting" prefHeight="35.0" prefWidth="225.0" text="确定" AnchorPane.bottomAnchor="27.0" AnchorPane.leftAnchor="100.0" AnchorPane.rightAnchor="100.0" />
</children>
<children>
<Button mnemonicParsing="false" opacity="0.0" text="避免聚焦" />
<AnchorPane fx:id="upSplite" opacity="0.45" prefHeight="80.0" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ImageView fx:id="miniLogo" fitHeight="35.0" fitWidth="35.0" layoutX="-50.0" layoutY="-47.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="2.0" AnchorPane.topAnchor="2.0" />
<Label layoutX="37.0" layoutY="12.0" prefHeight="35.0" text="文件管理系统" AnchorPane.leftAnchor="40.0" AnchorPane.topAnchor="2.0">
<font>
<Font name="Arial Black" size="12.0" />
</font></Label>
</children>
</AnchorPane>
<GridPane layoutX="152.0" layoutY="110.0" AnchorPane.bottomAnchor="65.0" AnchorPane.leftAnchor="80.0" AnchorPane.rightAnchor="80.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="108.0" minWidth="10.0" prefWidth="85.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="182.0" minWidth="10.0" prefWidth="140.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<TextField fx:id="ipAddress" GridPane.columnIndex="1" />
<Label text="后台IP地址" />
<Label text="后台端口号" GridPane.rowIndex="1" />
<Label text="服务前缀" GridPane.rowIndex="2" />
<TextField fx:id="packetPrefix" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<TextField fx:id="portAddress" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="文件传输并发数" GridPane.rowIndex="3" />
<TextField fx:id="fileThread" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Label text="区块链IP地址" GridPane.rowIndex="4" />
<Label text="区块链端口号" GridPane.rowIndex="5" />
<TextField fx:id="BlockIP" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<TextField fx:id="BlockPort" GridPane.columnIndex="1" GridPane.rowIndex="5" />
</children>
</GridPane>
<Button layoutX="112.0" layoutY="263.0" mnemonicParsing="false" onAction="#handleSetting" prefHeight="35.0" prefWidth="225.0" text="确定" AnchorPane.bottomAnchor="27.0" AnchorPane.leftAnchor="100.0" AnchorPane.rightAnchor="100.0" />
</children>
</AnchorPane>