多线程
作者原答案:多线程环境下,TrackerServerGroup必须每个线程一份。必须使用 fdfs_client_init_ex、tracker_get_connection_ex等函数。
在fastDFS中有一个 client_global.h的头文件,其中定义了一个全局变量
extern TrackerServerGroup g_tracker_group;
在**fdfs_client_init** **tracker_get_connection** 等宏展开成的时候会传入这个全局变量
define fdfs_client_init(filename) \
fdfs_client_init_ex((&g_tracker_group), filename)
define fdfs_client_init_from_buffer(buffer) \
fdfs_client_init_from_buffer_ex((&g_tracker_group), buffer)
define fdfs_client_destroy() \
fdfs_client_destroy_ex((&g_tracker_group))
如果要在多线程下使用fastdfs,那么就要在每个线程包含一份TrackerServerGroup,并且使用_ex后缀的函数,而不是宏
线程安全版
FastDfs.h
//// Created by wanghaitao on 2021/2/5.//#ifndef CLOUD_DISK_FASTDFS_H#define CLOUD_DISK_FASTDFS_H#include "fdfs_client.h"/*** local_filename不应超过64个字符*/class FastDfs {public:/*** 操作fastDfs的api类* 不使用持久连接,每次上传、删除等操作都开启一个新连接* 目前未提供下载的api* @param conf_fileName 配置文件的路径*/explicit FastDfs(const char * conf_fileName = nullptr);~FastDfs();/*** 通过文件名上传文件* @param local_filename 本地文件名,not null,小于 64字符* @param remote_filename 返回远程文件名,不带group, not null* @throw FastDfsException 上传不成功*/void file_upload_by_filename(const char * local_filename,char * remote_filename);/*** 通过文件缓存上传文件* @param buffer 文件缓存,not null* @param file_size 文件大小* @param local_filename 本地文件名,not null,小于 64字符* @param remote_filename 返回远程文件名,不带group, not null* @param meta_data 文件元数据,可以null* @param meta_count 元数据数量, 可以null// 元数据构造示例FDFSMetaData meta_data[Max_Meta_Date_num];int meta_count = 0;strcpy(meta_data[meta_count].name,"File");strcpy(meta_data[meta_count++].value,local_filename);* @throw FastDfsException 上传不成功*/void file_upload_by_buffer(const char * buffer,const int file_size, const char * local_filename, char * remote_filename,const FDFSMetaData * meta_data,const int meta_count);/*** 删除文件* @param remote_filename 要删除的远程文件名* @throw FastDfsException 删除出错*/void file_delete_by_remote_filename(const char * remote_filename);private:TrackerServerGroup tracker_group;};#endif //CLOUD_DISK_FASTDFS_H
Exceptions.h
class FastDfsException: public std::exception{public:const char * what() const noexcept override;explicit FastDfsException(int errorNumber):_what(strerror(errorNumber)){}explicit FastDfsException(const char * what):_what(what){}private:std::string _what;};
FastDfs.cpp
//// Created by wanghaitao on 2021/2/5.//#include "FastDfs.h"#include "Exceptions.h"#include "make_log.h"#include "tracker_proto.h"static const char *FastDfs_DEFAULT_CONF_FILENAME = "/etc/fdfs/client.conf";static const char *Log_Dir = "FastDfs";static const int Max_Meta_Date_num=5;FastDfs::FastDfs(const char * conf_fileName) {if (conf_fileName == nullptr)conf_fileName = FastDfs_DEFAULT_CONF_FILENAME;int code;if ((code = fdfs_client_init_ex(&tracker_group, conf_fileName)) != 0) {throw FastDfsException(code);}}FastDfs::~FastDfs() {fdfs_client_destroy_ex(&tracker_group);}void FastDfs::file_upload_by_filename(const char *local_filename, char *remote_filename) {if (local_filename == nullptr) {throw FastDfsException("on upload by filename: local filename should not be null");}if (remote_filename == nullptr) {throw FastDfsException("on upload by filename: remote filename should not be null");}char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];ConnectionInfo *pTrackerServer;int code;int store_path_index;ConnectionInfo storageServer;code = ignore_signal_pipe();if (code != 0) {LOG(Log_Dir, "filenameUploadErroe", "ignore signal pipe error");throw FastDfsException(code);}// 连tracker,然后连storagepTrackerServer = tracker_get_connection_ex(&tracker_group);if (pTrackerServer == nullptr) {code = errno != 0 ? errno : ECONNREFUSED;LOG(Log_Dir, "filenameUploadErroe", "connect to track server error, error info: %s", strerror(code));throw FastDfsException(code);}*group_name = '\0';if ((code = tracker_query_storage_store(pTrackerServer, \&storageServer, group_name, &store_path_index)) != 0) {LOG(Log_Dir, "filenameUploadErroe", "tracker_query_storage fail, error info: %s\n", strerror(code));throw FastDfsException(code);}// 传文件code = storage_upload_by_filename1_ex(pTrackerServer,&storageServer, store_path_index,STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE, local_filename,nullptr, nullptr, 0, group_name, remote_filename);tracker_disconnect_server_ex(pTrackerServer, true);if (code != 0) {LOG(Log_Dir, "filenameUploadErroe", "upload file fail, error info: %s\n", strerror(code));throw FastDfsException(code);}}void FastDfs::file_upload_by_buffer(const char *buffer,const int file_size, const char *local_filename, char *remote_filename,const FDFSMetaData * meta_data,const int meta_count) {if (local_filename == nullptr) {throw FastDfsException("on upload by buffer: local filename should not be null");}if (remote_filename == nullptr) {throw FastDfsException("on upload by buffer: remote filename should not be null");}if (buffer == nullptr) {throw FastDfsException("on upload by buffer: buffer should not be null");}char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];ConnectionInfo *pTrackerServer;int code;int store_path_index;ConnectionInfo storageServer;code = ignore_signal_pipe();if (code != 0) {LOG(Log_Dir, "bufferUploadError", "ignore signal pipe error");throw FastDfsException(code);}// 连tracker,然后连storagepTrackerServer = tracker_get_connection_ex(&tracker_group);if (pTrackerServer == nullptr) {code = errno != 0 ? errno : ECONNREFUSED;LOG(Log_Dir, "bufferUploadError", "connect to track server error, error info: %s", strerror(code));throw FastDfsException(code);}*group_name = '\0';if ((code = tracker_query_storage_store(pTrackerServer, \&storageServer, group_name, &store_path_index)) != 0) {LOG(Log_Dir, "bufferUploadError", "tracker_query_storage fail, error info: %s\n", strerror(code));throw FastDfsException(code);}// 生成文件扩展名const char * file_ext_name = nullptr;file_ext_name = strrchr(local_filename,'.');if(file_ext_name!= nullptr)++file_ext_name;// 传文件code = storage_upload_by_filebuff1(pTrackerServer, &storageServer,store_path_index, buffer, file_size,file_ext_name, meta_data, meta_count, group_name, remote_filename);tracker_disconnect_server_ex(pTrackerServer, true);if (code != 0) {LOG(Log_Dir, "bufferUploadError", "upload buffer file fail, error info: %s\n", strerror(code));throw FastDfsException(code);}}void FastDfs::file_delete_by_remote_filename(const char *remote_filename) {if (remote_filename== nullptr){throw FastDfsException("remote_filename should be null");}ConnectionInfo *pTrackerServer;int code;code = ignore_signal_pipe();if (code != 0) {LOG(Log_Dir, "deleteError", "ignore signal pipe error");throw FastDfsException(code);}pTrackerServer = tracker_get_connection_ex(&tracker_group);if (pTrackerServer == nullptr) {code = errno != 0 ? errno : ECONNREFUSED;LOG(Log_Dir, "deleteError", "connect to track server error, error info: %s", strerror(code));throw FastDfsException(code);}code=storage_delete_file1(pTrackerServer, nullptr, remote_filename);tracker_disconnect_server_ex(pTrackerServer, true);if (code != 0) {LOG(Log_Dir, "deleteError", "upload buffer file fail, error info: %s\n", strerror(code));throw FastDfsException(code);}}
其他问题
storage_upload_by_filename1与 storage_upload_by_filename区别:
加1的前面带group name,不加1的不带,推荐用storage_upload_by_filebuff

ubuntu@VM-0-7-ubuntu:/usr/local/src/fastDfs_package/01_fdfs/fastdfs-5.10/client$ ./fdfs_upload_file /etc/fdfs/client.conf ./fdfs_upload_file.cM00/00/00/rBAAB2AcCTSAbqN9AAAKGKVbM_I58860.cubuntu@VM-0-7-ubuntu:/usr/local/src/fastDfs_package/01_fdfs/fastdfs-5.10/client$ fdfs_upload_file /etc/fdfs/client.conf ./fdfs_upload_file.cgroup1/M00/00/00/rBAAB2AcCTqARR21AAAKGKVbM_I63529.c
其中第一个是不带1的,第二个是带1的
