参考博客:https://www.cnblogs.com/ityouknow/p/8123998.html
参考博客:https://www.cnblogs.com/gne-hwz/p/9513255.html
原因分析:本次项目中需要将文件上传到fastdfs,由于上传文件大小不一,且涉及到线程的问题,出现了此问题。
情况一:
问题排查:此项目为多线程,当第一次初始化时,new 了tranckerClient,trackerServer,storageClient实例,当第一次调用时被初始化赋值,因为StorageClient对象只new一次,在多线程环境中,我加入了试错机制,当第一个上传失败时,试错机制启动,此时就会报recv pack size -1 !=10,并伴随有nullPointException。
/*
* 静态初始化
* 1加载配置文件
* 2初始化 调度器客户端、服务端以及存储客户端服务端
*/
/**
* <b>FastDFS 初始化</b><br>
*/
public static void init() {
try {
String classPath = new File(FileManager.class.getResource("/").getFile()).getCanonicalPath();
String fdfsClientConfigFilePath = classPath + File.separator + "configs.properties";
ClientGlobal.init(fdfsClientConfigFilePath);
trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
storageClient = new StorageClient1(trackerServer, storageServer);
// ProtoCommon.activeTest(storageServer.getSocket());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* <b>上传文件到文件服务器</b><br>
* @param file 文件
* @param filename 文件名
* @param fileType 文件类型
* @return 文件完整的HTTP访问路径
*/
public static String uploadFile(File file, String filename, String fileType) {
FastDFSFile fdsfFile = new FastDFSFile(File2byte(file), fileType);
NameValuePair[] meta_list = new NameValuePair[2];
meta_list[0] = new NameValuePair("fileName", filename);
meta_list[1] = new NameValuePair("fileType", fileType);
String[] uploadResults = null;
try {
uploadResults = storageClient.upload_file(fdsfFile.getContent(), fdsfFile.getExt(), meta_list);
} catch (Exception e) {
logger.error("filename:{},上传失败,异常:{}", filename, e);
e.printStackTrace();
}
String groupName = uploadResults[0];
String remoteFileName = uploadResults[1];
String fileAbsolutePath = PROTOCOL + TRACKER_NGNIX_ADDR
+ SEPARATOR + groupName + SEPARATOR + remoteFileName;
System.out.println("fileAbsolutePath"+fileAbsolutePath);
return fileAbsolutePath;
}
解决办法:
FileManager是我们封装好的FastDFS工具类,在启动的时候会对storageClient进行初始化,这样每次项目调研的时候都会复用storageClient实例。upload()方法每次会从全局变量中获取storageClient进行调用,也就意味着每次请求使用的是同一个storageClient实例,当然也包括实例中的变量storageServer。
每次调用的时候进行一次初始化
//添加在调用upload方法之前
init();