因为在做的项目中有这么一个模块,有3个等级的服务 sc、occ、 tcc sc与occ采用tcp连接 occ 与tcc 也采用tcp连接。
操作者录完音要把录音文件直接从sc上报到tcc 中间会经过occ
那么流程就是 从sc 上报给occ 到了occ以后从ftp中根据ftp的地址、用户名、密码来将文件下载到本地。下载到本地,后再继续向上级tcc上报。
ftp下载的方法:
@Override
public void run() {
while (isRunning) {
try
{
//取消息并分发处理
MaterialFileInfo fileInfo = getFile();
if (null != fileInfo) {
if (downloadFile(fileInfo)) {
Ftp1 m = new Ftp1(fileInfo.getFtpUrl(), fileInfo.getPort(), fileInfo.getUser(),
fileInfo.getPassword());
String filePath = fileInfo.getFilePath();
// 素材文件在本机的根目录
String materialSaveMainPath = ParamManager.materialSaveMainPath;
String[] strings = filePath.replaceAll("\\\\", "/").split("/");
String stirng2 = "";// 素材在ftp上的目录
for (int i = 0; i < strings.length - 1; i++) {
String string = strings[i];
stirng2 += "\\" + string;
}
// 文件名称:a.mp3
String string1 = strings[strings.length - 1];
// 素材文件的下载位置
String downloadPath = materialSaveMainPath + stirng2.replaceAll("\\\\", "");
// 如果目录不存在就创建目录
File myPath = new File(downloadPath);
if (!myPath.exists()) {
myPath.mkdirs();
}
m.getFile2(stirng2, string1, downloadPath + "/" + string1);
/**
* 如果素材下载失败,本地没有这个素材,放入队列中重试
*/
noExistsRetry(fileInfo, downloadPath,string1);
}
}
Thread.sleep(10);
}
catch (java.lang.Throwable e)
{
e.printStackTrace();
}
finally
{
}
if (isRunning == false)
{
if (this.fileQueue.getNum() == 0)
{
break;
}
}
}
cleanUp();
}
因为我们从ftp下载用的是线程,所以在开发的过程中遇到一个问题,程序的执行是很快的,下载的过程在我们的代码中不过就是一句话交给了线程去做,然后就继续上报。
那么就会有很大的可能性:我们的occ还没有从sc的ftp上下载,或者是还没有下载完到本地的时候就已经执行了向tcc继续上报的动作。 那么tcc从occ的ftp上下载的时候肯定是找不到下载不下来的,或者是下载的是一个0字节的空文件。
解决方法有很多种:
1、将ftp下载的方法改为普通的方法。不再使用线程。 后果:影响其他的模块,并不是只有我这一个模块会用到ftp下载且改为普通方法 就会变成同步的操作,如果有大量的录音同时上报 会影响程序的流畅性。
2、sleep(1000),让程序的主线程休息1秒,或者是休息其他的时间,也不太可行,因为录音的文件有大有小,并不是所有的录音都是一秒或者几秒可以下载完毕。还是会有下载的不全的情况发生。
3、每隔1秒,检验录音在本地是否下载完成,下载完成的话再继续上报。若超过20s还未能下载完成,那么打印日志记录并返回false。
最终采用了第3种方法,可以及时的上报,且有20s限制不会一直因为一个录音而阻塞。
详细代码:
// 继续看本级节点有没有连接上级的节点 有的话继续向上发
public boolean ContinueSendManageNode(List<RecordInfo> recInfoList) throws InterruptedException {
//校验文件在本地是否下载成功
String sRecPath = ParamManager.materialSaveMainPath;
File file = new File(sRecPath + recInfoList.get(0).getRecFileName());
int i = 0;
while (true) {
if (file.renameTo(file)) {
break;
} else {
i++;
Thread.sleep(1000);
}
if (i >= 20) {
logger.info(new Date() + ":" + recInfoList.get(0).getRecName() + "录音下载本地失败");
return false;
}
}
//保存下级上报后 继续看本级节点有没有连接上级的节点 有的话继续向上发
List<SystemNodeInfo> serverNodes = DataCache.newInstance().getServerNodes(ServerType.MANAGE_SERVER);
if (!serverNodes.isEmpty()&&serverNodes.size()!=0) {
RecordListUploadDispatcher.getInstance().sendRecord(recInfoList);
}
return true;
}