C++文件服务器项目—FastDFS—1

2023-05-16

C++文件服务器项目—FastDFS—1

  • 前言
  • 1. 项目架构
  • 2. 分布式文件系统
    • 2.1 传统文件系统
    • 2.2 分布式文件系统
  • 3. FastDFS介绍
    • 3.1 fdfs概述
    • 3.2 fdfs框架中的三个角色
    • 3.3 fdfs三个角色之间的关系
    • 3.4 fdfs集群
  • 4. FastDFS的安装
    • 4.1 源码安装详解
    • 4.2 安装源码
    • 4.3 make install做了哪些事
    • 4.4 测试
  • 5. fdfs的配置文件
    • 5.1 tracker配置文件
    • 5.2 storage配置文件
    • 5.3 client配置文件
    • 5.4 集群的配置
  • 6. fdfs的启动
    • 6.1 第一个启动追踪器 - 守护进程
    • 6.2 第二个启动存储节点 - 守护进程
    • 6.3 第三个启动客户端 - 普通进程
    • 6.4 FastDFS的状态检测
  • 7. file_id的构成
  • 8. 上传下载的代码实现
    • 8.1 使用多进程方式-思路
    • 8.2 使用fastDFS API实现-思路
    • 8.3 两个方案的代码实现
      • 8.3.1 源代码
      • 8.3.2 测试

前言

   本项目使用c++实现一个文件服务器,核心功能是上传与下载。所以该项目可以作为网盘,也可以作为图床来用。

  本文的核心重点是介绍FastDFS概念构成配置文件启动上传下载的实现。后续将逐步介绍nginx,mysql,redis,fastcgi等内容。

  本专栏知识点是通过零声教育的线上课学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接 C/C++后台高级服务器课程介绍 详细查看课程的服务。

1. 项目架构

项目架构图

  1. 客户端-网络架构
  • b/s:浏览器使用http协议
  • c/s:客户端可以随意选择协议
  1. 反向代理服务器
  • 客户端并不能直接访问web服务器, 直接访问到的是反向代理服务器
  • 客户端静请求发送给反向代理服务器, 反向代理将客户端请求转发给web服务器
  1. 服务端
  • Nginx

    • 可以处理静态请求:html,jpg
    • 无法处理动态请求
    • 服务器部署为集群后, 每台服务器上部署的内容必须相同
  • fastCGI

    • 帮助服务器Nginx处理动态请求
  1. 关系型数据库mysql
  • 存储文件的属性信息
  • 存储用户的属性信息
  1. 非关系型数据库redis
  • 提高程序效率,减轻mysql压力
  • 存储是服务器经常要从关系型数据中读取的数据
  1. FastDFS - 分布式文件系统
  • 存储用户上传的文件
  • 用户下载存储的文件

2. 分布式文件系统

2.1 传统文件系统

在这里插入图片描述
   传统的文件系统可以被挂载和卸载,格式:ntfs / fat32 / ext3 / ext4

   一台主机的磁盘插槽不可能是无限的,当磁盘都满了之后想要扩充,而磁盘插槽都被插满了,那么这个时候就需要使用分布式文件系统了。

2.2 分布式文件系统

   完整的文件系统, 不在同一台主机上,而是在很多台主机上,多个分散的文件系统组合在一起,形成了一个完整的文件系统。

在这里插入图片描述

分布式文件系统:

  1. 需要有网络
  2. 多台主机(不需要在同一地点)
  3. 需要管理者,管理所有的存储节点
  4. 编写应用层的管理程序(Ceph,TFS,FastDFS,MogileFS,MooseFS,GlusterFS)

3. FastDFS介绍

3.1 fdfs概述

  • 是用c语言编写的一款开源的分布式文件系统。
    • 余庆 - 淘宝的架构师
  • 为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,注重高可用、高性能等指标
    • 冗余备份: 纵向扩容
    • 线性扩容: 横向扩容
  • 可以很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
    • 图床
    • 网盘

3.2 fdfs框架中的三个角色

  • 追踪器 ( tracker ) - 管理者 - 守护进程
    • 管理存储节点,可以有多个
  • 存储节点(storage )- 守护进程
    • 存储节点是有多个的
  • 客户端(client) - 不是守护进程, 这是程序猿编写的程序
    • 文件上传
    • 文件下载

3.3 fdfs三个角色之间的关系

上传

  • 上传

下载

  • 下载
  1. 追踪器 (tracker)

    • 最先启动追踪器(存储节点和客户端都需要主动连接追踪器)
  2. 存储节点(storage )

    • 第二个启动的角色
    • 存储节点启动之后, 会单独开一个线程
      • 汇报当前存储节点的容量, 和剩余容量
      • 汇报数据的同步情况
      • 汇报数据被下载的次数
  3. 客户端

    • 最后启动
    • 上传
      • 连接追踪器, 询问存储节点的信息
        • 我要上传1G的文件, 询问哪个存储节点有足够的容量
        • 追踪器查询, 得到结果
        • 追踪器将查到的存储节点的IP+端口发送给客户端
        • 通过得到IP和端口连接存储节点
        • 将文件内容发送给存储节点
    • 下载
      • 连接追踪器, 询问存储节点的信息
        • 问一下, 要下载的文件在哪一个存储节点
        • 追踪器查询, 得到结果
        • 追踪器将查到的存储节点的IP+端口发送给客户端
        • 通过得到IP和端口连接存储节点
        • 下载文件

3.4 fdfs集群

在这里插入图片描述

  1. 追踪器集群
    • 为什么需要追踪器集群?

      • 避免单点故障
    • 多个tracker如何工作?

      • 轮询RR
    • 如何实现集群

      • 通过修改配置文件可实现

  

  1. 存储节点集群

    • fastDFS如何管理存储节点?

      • 通过分组的方式完成的(Group)
    • 集群方式(两种扩容方式)

      • 横向扩容 - 增加容量
      • 纵向扩容 - 数据备份
    • 如何实现集群

      • 通过修改配置文件可实现

横向扩容 - 增加容量:

假设当前有两个组: group1, group2
需要添加一个新的分组 -> group3
新主机属于group3

添加一台新的主机 -> 容量增加了

不同组的主机之间不需要通信

纵向扩容 - 数据备份:

假设当前有两个组: group1, group2
将新的主机放到现有的组中

每个组的主机数量从1 -> N
- 这n台主机的关系就是相互备份的关系
- 同一个组中的主机需要通信
- 每个组的容量 等于 组内容量最小的主机容量(比如Group1的容量是500G)

4. FastDFS的安装

4.1 源码安装详解

安装流程:

  1. 以下文件, 里边有安装步骤
    • readme
    • readme.md
    • INSTALL
  2. 找 可执行文件 configure
    • 执行这个可执行文件
      • 检测安装环境
      • 生成 makefile
  3. 执行make命令
    • 编译源代码
      • 生成动态库或静态库
      • 生成可执行程序
  4. 安装 make install (需要管理员权限)
    • 将第三步生成的动态库/动态库/可执行程序拷贝到对应的系统目录

4.2 安装源码

  1. 安装 libfastcommon(fastdfs的基础库包)
git clone https://github.com/happyfish100/libfastcommon.git

cd libfastcommon

./make.sh
./make.sh install
  1. 安装 FastDFS
git clone https://gitee.com/fastdfs100/fastdfs.git

cd fastdfs

./make.sh
./make.sh install

4.3 make install做了哪些事

来看看make install都做了哪些事情

在这里插入图片描述

在这里插入图片描述

4.4 测试

测试

fdfs_test

ls /usr/bin/fdfs_*
root@wxf:/# fdfs_test
This is FastDFS client test program v6.08

Copyright (C) 2008, Happy Fish / YuQing

FastDFS may be copied only under the terms of the GNU General
Public License V3, which may be found in the FastDFS source kit.
Please visit the FastDFS Home Page http://www.fastken.com/ 
for more detail.

Usage: fdfs_test <config_file> <operation>
	operation: upload, download, getmeta, setmeta, delete and query_servers

#fastDFS安装的所有的可执行程序: 
root@wxf:/# ls /usr/bin/fdfs_*
/usr/bin/fdfs_appender_test   /usr/bin/fdfs_download_file        /usr/bin/fdfs_test
/usr/bin/fdfs_appender_test1  /usr/bin/fdfs_file_info            /usr/bin/fdfs_test1
/usr/bin/fdfs_append_file     /usr/bin/fdfs_monitor              /usr/bin/fdfs_trackerd
/usr/bin/fdfs_crc32           /usr/bin/fdfs_regenerate_filename  /usr/bin/fdfs_upload_appender
/usr/bin/fdfs_delete_file     /usr/bin/fdfs_storaged             /usr/bin/fdfs_upload_file

  为什么在别的目录输入fdfs_test 也能执行?因为make install的时候,已经将程序拷贝到/usr/bin目录下了。

root@wxf:/temp/fastdfs# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

5. fdfs的配置文件

  在上面已经分析了fdfs的配置文件放在/etc/fdfs/目录下。

root@wxf:/etc/fdfs# ls
client.conf  storage.conf  storage_ids.conf  tracker.conf

5.1 tracker配置文件

  不同的tracker主机需要各自修改自己的配置文件

# 下列是需要修改的地方

# 将追踪器和部署的主机的IP地址进程绑定, 也可以不指定
# 如果不指定, 会自动绑定当前主机IP, 如果是云服务器建议不要写
# 这里的ip和port是提供给storage,client建立连接用的
bind_addr=192.168.109.100
# 追踪器监听的端口
port=22122
# 追踪器存储日志信息的目录, xxx.pid文件, 必须是一个存在的目录
base_path=/fastdfs/tracker

   这里因为fastdfs由client,storage,tracker构成,所以可以创建一个fastdfs目录,里面再分三个子目录,由一个大目录fastdfs进行统一管理。

在这里插入图片描述

5.2 storage配置文件

  不同的storage主机需要各自修改自己的配置文件

# 下列是需要修改的地方

# 当前存储节点对应的主机属于哪一个组
group_name=group1
# 当前存储节点和所应该的主机进行IP地址的绑定, 如果不写, 有fastdfs自动绑定
# 这里的ip和port是给client建立连接用的
bind_addr=
# 存储节点绑定的端口
port=23000
# 存储节点写log日志的路径
base_path=/fastdfs/storage
# 存储节点提供的存储文件的路径个数
store_path_count=2
# 具体的存储路径 【M00 M01映射的路径】
store_path0=/fastdfs/storage0
store_path1=/fastdfs/storage1
# 追踪器的地址信息
tracker_server=192.168.109.100:22122 
tracker_server=192.168.109.101:22122 

   上面配置两个存储目录和两个追踪器地址只是演示怎么配置而已,后文用的配置如下

# 存储节点写log日志的路径
base_path=/fastdfs/storage
# 存储节点提供的存储文件的路径个数
store_path_count=1
# 具体的存储路径 【M00 M01映射的路径】
store_path0=/fastdfs/storage
# 追踪器的地址信息
tracker_server=192.168.109.100:22122 

5.3 client配置文件

# 下列是需要修改的地方

# 客户端写log日志的目录
# 该路径必须存在
# 当前的用户对于该路径中的文件有读写权限
base_path=/fastdfs/client
# 要连接的追踪器的地址信息
tracker_server=192.168.109.100:22122 
tracker_server=192.168.109.101:22122 

5.4 集群的配置

  假设现在有6台主机,2台client,2台tracker,2台storage。

  第一步:6台主机全部安装FastDFS

  第二步:修改各自对应的配置文件

在这里插入图片描述

6. fdfs的启动

所有的启动程序都在/usr/bin/目录下

root@wxf:/# ls /usr/bin/fdfs_*
/usr/bin/fdfs_appender_test   /usr/bin/fdfs_download_file        /usr/bin/fdfs_test
/usr/bin/fdfs_appender_test1  /usr/bin/fdfs_file_info            /usr/bin/fdfs_test1
/usr/bin/fdfs_append_file     /usr/bin/fdfs_monitor              /usr/bin/fdfs_trackerd
/usr/bin/fdfs_crc32           /usr/bin/fdfs_regenerate_filename  /usr/bin/fdfs_upload_appender
/usr/bin/fdfs_delete_file     /usr/bin/fdfs_storaged             /usr/bin/fdfs_upload_file

   其实下面命令中不指定/usr/bin也可以,我这里为了演示清楚目录,全部补全了。

6.1 第一个启动追踪器 - 守护进程

# 使用的方式如下
# <程序> <配置文件> <行为>

# 启动
#fdfs_trackerd 追踪器的配置文件(/etc/fdfs/tracker.conf) 
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start

# 关闭
#fdfs_trackerd 追踪器的配置文件(/etc/fdfs/tracker.conf) stop
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf stop

# 重启
#fdfs_trackerd 追踪器的配置文件(/etc/fdfs/tracker.conf) restart
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart

6.2 第二个启动存储节点 - 守护进程

# 使用的方式如下
# <程序> <配置文件> <行为>

# 启动
#fdfs_storaged 存储节点的配置文件(/etc/fdfs/stroga.conf)
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf start

# 关闭
#fdfs_storaged 存储节点的配置文件(/etc/fdfs/stroga.conf) stop
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf stop

# 重启
#fdfs_storaged 存储节点的配置文件(/etc/fdfs/stroga.conf) restart
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart

6.3 第三个启动客户端 - 普通进程

# 使用的方式如下
# <程序> <配置文件> <行为>

# 上传
#fdfs_upload_file 客户端的配置文件(/etc/fdfs/client.conf) 要上传的文件(/etc/fdfs/client.conf)
# 得到的结果字符串: group1/M00/00/00/wKhtZWMVtDGAR4d0AAAHTaCnXjs12.conf
root@wxf:/# /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /etc/fdfs/client.conf 
group1/M00/00/00/wKhtZWMVtDGAR4d0AAAHTaCnXjs12.conf
# 下载
#fdfs_download_file 客户端的配置文件(/etc/fdfs/client.conf) 上传成功之后得到的字符串(fileID)
root@wxf:/# /usr/bin/fdfs_download_file /etc/fdfs/client.conf group1/M00/00/00/wKhtZWMVtDGAR4d0AAAHTaCnXjs12.conf
root@wxf:/# ls
wKhtZWMVtDGAR4d0AAAHTaCnXjs12.conf
# 发现原来的文件名被修改了,所以需要把原来的文件名和保证之后的文件名做一个映射保存在数据库中

在这里插入图片描述

6.4 FastDFS的状态检测

  1. 实现使用工具查看一下是否启动成功
#查看端口是否被占用:
netstat -apn | grep 80
	
#查看占用某个端口的进程:
sudo lsof -i:80
	
#关键字搜索某个进程
ps -aux | grep fdfs


lsof -i:22122
lsof -i:23000
ps aux|grep fdfs_

在这里插入图片描述

  1. 使用fdfs_monitor检测fastDFS状态
fdfs_monitor /etc/fdfs/client.conf

   可以看到fdfs_monitor 后面跟的是client的配置信息,所以可以把它当作一个客户端,启动时先连接追踪器,向追踪器询问storage的信息

在这里插入图片描述

   STORAGE SERVER的状态通常有七种,正常状态必须是ACTIVE

# FDFS_STORAGE_STATUS:INIT      :初始化,尚未得到同步已有数据的源服务器
# FDFS_STORAGE_STATUS:WAIT_SYNC :等待同步,已得到同步已有数据的源服务器
# FDFS_STORAGE_STATUS:SYNCING   :同步中
# FDFS_STORAGE_STATUS:DELETED   :已删除,该服务器从本组中摘除
# FDFS_STORAGE_STATUS:OFFLINE   :离线
# FDFS_STORAGE_STATUS:ONLINE    :在线,尚不能提供服务
# FDFS_STORAGE_STATUS:ACTIVE    :在线,可以提供服务
# 从集群中删除
fdfs_monitor /etc/fdfs/client.conf delete group1 192.168.109.100

# 删除数据文件夹
rm -rf /fastdfs/storage/data

# 重启节点
fdfs_storaged /etc/fdfs/storage.conf restart

7. file_id的构成

在这里插入图片描述

  • group1
    • 文件上传到了存储节点的哪一个组
    • 如果有多个组这个组名可变的

  

  • M00 - 虚拟目录

    • 和存储节点的配置项有映射
      • store_path0=/home/yuqing/fastdfs/data -> M00
        store_path1=/home/yuqing/fastdfs1/data -> M01
          
  • 00/00

    • 实际的路径
    • 可变的

  

  • wKhS_VlrEfOAdIZyAAAJTOwCGr43848.md
    • 文件名包含的信息
    • 采用Base64编码
      • 包含的字段包括
        • 源storage server Ip 地址
        • 文件创建时间
        • 文件大小
        • 文件CRC32效验码(循环冗余校验)
        • 随机数
wKhS_VlrEfOAdIZyAAAJTOwCGr43848
| 4bytes | 4bytes | 8bytes |4bytes | 2bytes |
| ip | timestamp | file_size |crc32 | 校验值 |

8. 上传下载的代码实现

8.1 使用多进程方式-思路

   我们上面已经用过fdfs_upload_file了,这是fdfs作者提供好的可执行程序,所以用多进程的方式是一种比较投机的方式。将fdfs_upload_file的输出重定位到管道pipe,由父进程读取。
在这里插入图片描述
   exec函数协议族函数(exec族函数用一个新的进程映像替换当前进程映像):execl、execlp。

  子进程 -> 执行execlp("fdfs_upload_file" , "xx", arg, NULL)。此时会有结果输出到标准输出终端里面,我们想让它输出到终端,使用dup2(old标准输出, new管道的写端)。将file_id写入pipe中,最终由父进程进行读取。pipe在子进程创建之前创建即可。父进程记得还要wait(),释放子进程的资源。

  • 操作步骤

    1. 创建管道 - pipe

    2. 创建子进程

    3. 子进程干什么?

      • 写管道, 关闭读端
        • 将标准输出 -> 管道的写端
      • 重定向
      • 执行execl命令, 调用另外的进程fdfs_upload_file
      • 子进程退出
    4. 父进程?

      • 读管道, 关闭写端
      • 释放子进程资源 - pcb
        • wait()/ waitpid()

8.2 使用fastDFS API实现-思路

  作者并没有提供api与文档出来,但是我们可以通过fdfs_upload_file.c,看看源码是怎么做的。

在这里插入图片描述

   看我写的//TODO 注释即可。那么我们的思路就很简单,把这个main函数改成一个接口即可。

/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
**/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fdfs_client.h"
#include "fastcommon/logger.h"

static void usage(char *argv[]) {
    printf("Usage: %s <config_file> <local_filename> " \
        "[storage_ip:port] [store_path_index]\n", argv[0]);
}

int main(int argc, char *argv[]) {
    char *conf_filename;
    char *local_filename;
    char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
    ConnectionInfo *pTrackerServer;
    int result;
    int store_path_index;
    ConnectionInfo storageServer;
    char file_id[128];

    if (argc < 3) {
        usage(argv);
        return 1;
    }

    log_init();
    g_log_context.log_level = LOG_ERR;
    ignore_signal_pipe();

    conf_filename = argv[1];
    //TODO fdfs_client_init解析传入的配置文件
    if ((result = fdfs_client_init(conf_filename)) != 0) {
        return result;
    }
    //TODO tracker_get_connection在上面client配置文件里面
    //TODO 有追踪器的ip:port,所以这里就是连接追踪器,初始化pTrackerServer指针
    pTrackerServer = tracker_get_connection();
    if (pTrackerServer == NULL) {
        fdfs_client_destroy();
        return errno != 0 ? errno : ECONNREFUSED;
    }

    local_filename = argv[2];
    *group_name = '\0';
    //我们都是传3个参数,这里>=4不用看了
    if (argc >= 4) {
        const char *pPort;
        const char *pIpAndPort;

        pIpAndPort = argv[3];
        pPort = strchr(pIpAndPort, ':');
        if (pPort == NULL) {
            fdfs_client_destroy();
            fprintf(stderr, "invalid storage ip address and " \
                "port: %s\n", pIpAndPort);
            usage(argv);
            return 1;
        }

        storageServer.sock = -1;
        snprintf(storageServer.ip_addr, sizeof(storageServer.ip_addr), \
             "%.*s", (int) (pPort - pIpAndPort), pIpAndPort);
        storageServer.port = atoi(pPort + 1);
        if (argc >= 5) {
            store_path_index = atoi(argv[4]);
        }
        else {
            store_path_index = -1;
        }
    }
        //TODO tracker_query_storage_store追踪器 查询 存储节点 的 存储
        //TODO storageServer是传入参数,对storageServer赋值
        //TODO group_name是一个char数组,对group_name赋值
        //TODO store_path_index是传入参数,对store_path_index赋值
    else if ((result = tracker_query_storage_store(pTrackerServer, \
                    &storageServer, group_name, &store_path_index)) != 0) {
        fdfs_client_destroy();
        fprintf(stderr, "tracker_query_storage fail, " \
            "error no: %d, error info: %s\n", \
            result, STRERROR(result));
        return result;
    }
    //TODO storage_upload_by_filename1查到了存储节点,就进行上传的动作
    //TODO file_id传出参数,如果上传成功了,就打印file_id
    result = storage_upload_by_filename1(pTrackerServer, \
            &storageServer, store_path_index, \
            local_filename, NULL, \
            NULL, 0, group_name, file_id);
    if (result == 0) {
        printf("%s\n", file_id);
    }
    else {
        fprintf(stderr, "upload file fail, " \
            "error no: %d, error info: %s\n", \
            result, STRERROR(result));
    }
    //TODO tracker_close_connection_ex与追踪器断开连接
    tracker_close_connection_ex(pTrackerServer, true);
    fdfs_client_destroy();

    return result;
}

8.3 两个方案的代码实现

8.3.1 源代码

  • fdfs_upload_file.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fdfs_client.h"
#include <sys/wait.h>

//使用多进程方式
int upload_file1(const char *confFile, const char *uploadFile, char *fileID, int size) {
    //1. 创建管道
    int fd[2];
    int ret = pipe(fd);
    if (ret == -1) {
        perror("pipe error");
        exit(0);
    }
    //2. 创建子进程
    pid_t pid = fork();
    //子进程
    if (pid == 0) {
        //3. 标准输出重定向 -> pipe写端
        dup2(fd[1], STDOUT_FILENO);
        //4. 关闭读端
        close(fd[0]);
        execlp("fdfs_upload_file", "fdfs_upload_file", confFile, uploadFile, NULL);
        perror("execlp error");
    }
    else {
        //父进程读管道
        close(fd[1]);
        read(fd[0], fileID, size);
        //回收子进程的PCB
        wait(NULL);
    }

}

//使用fastDFS API实现
int upload_file2(const char *confFile, const char *myFile, char *fileID) {
    char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
    ConnectionInfo *pTrackerServer;
    int result;
    int store_path_index;
    ConnectionInfo storageServer;

    //TODO fdfs_client_init解析传入的配置文件
    if ((result = fdfs_client_init(confFile)) != 0) {
        return result;
    }
    //TODO tracker_get_connection在上面client配置文件里面
    //TODO 有追踪器的ip:port,所以这里就是连接追踪器,初始化pTrackerServer指针
    pTrackerServer = tracker_get_connection();
    if (pTrackerServer == NULL) {
        fdfs_client_destroy();
        return errno != 0 ? errno : ECONNREFUSED;
    }

    *group_name = '\0';

    //TODO tracker_query_storage_store追踪器 查询 存储节点 的 存储
    //TODO storageServer是传入参数,对storageServer赋值
    //TODO group_name是一个char数组,对group_name赋值
    //TODO store_path_index是传入参数,对store_path_index赋值
    if ((result = tracker_query_storage_store(pTrackerServer, \
                    &storageServer, group_name, &store_path_index)) != 0) {
        fdfs_client_destroy();
        fprintf(stderr, "tracker_query_storage fail, " \
            "error no: %d, error info: %s\n", \
            result, STRERROR(result));
        return result;
    }
    //TODO storage_upload_by_filename1查到了存储节点,就进行上传的动作
    //TODO file_id传出参数,如果上传成功了,就打印file_id
    result = storage_upload_by_filename1(pTrackerServer, \
            &storageServer, store_path_index, \
            myFile, NULL, \
            NULL, 0, group_name, fileID);
    if (result == 0) {
        printf("%s\n", fileID);
    }
    else {
        fprintf(stderr, "upload file fail, " \
            "error no: %d, error info: %s\n", \
            result, STRERROR(result));
    }
    //TODO tracker_close_connection_ex与追踪器断开连接
    tracker_close_connection_ex(pTrackerServer, true);
    fdfs_client_destroy();

    return result;
}
  • fdfs_upload_file.h
//
// Created by 68725 on 2022/9/5.
//

#ifndef FDFS_UPLOAD_FILE_H
#define FDFS_UPLOAD_FILE_H

extern int upload_file1(const char *confFile, const char *uploadFile, char *fileID, int size);

extern int upload_file2(const char *confFile, const char *myFile, char *fileID);

#endif //FDFS_UPLOAD_FILE_H

  • main.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "fdfs_upload_file.h"

int main() {
    char fildID[1024] = {0};
    upload_file1("/etc/fdfs/client.conf", "main.c", fildID, sizeof(fildID));
    printf("Multiprocess upload_file1 fildID:%s\n", fildID);
    printf("=================================\n");
    upload_file2("/etc/fdfs/client.conf", "main.c", fildID);
    printf("Call API upload_file2 fildID:%s\n", fildID);
}

8.3.2 测试

root@wxf:/test# ls
fdfs_upload_file.c  fdfs_upload_file.h  main.c
root@wxf:/test# gcc -o test *.c -I/usr/include/fastdfs/ -lfdfsclient
root@wxf:/test# ls
fdfs_upload_file.c  fdfs_upload_file.h  main.c  test
root@wxf:/test# ./test 

Multiprocess upload_file1 fildID:group1/M00/00/00/wKhtZWMV4USAeXL4AAACCAMe_TM89174.c

=================================
group1/M00/00/00/wKhtZWMV4UWAeb7BAAACCAMe_TM19985.c
Call API upload_file2 fildID:group1/M00/00/00/wKhtZWMV4UWAeb7BAAACCAMe_TM19985.c

在这里插入图片描述

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++文件服务器项目—FastDFS—1 的相关文章

  • Missing artifact org.csource:fastdfs-client-java:jar:1.27-SNAPSHOT

    解决Maven无法下载fastdfs client java依赖 xff0c Dependency 39 org csource fastdfs client java 1 27 SNAPSHOT 39 not found 因为fastdf
  • docker搭建fastdfs环境

    fastdfs是一个开源的分布式文件系统 xff0c 在实际使用中 xff0c 通过源码编译安装过程非常复杂 xff0c 但是通过docker快速构建却非常容易 下面介绍通过docker安装fastdfs的方法 docker镜像的选择也挺重
  • C++文件服务器项目—项目总结与反向代理—7

    C 43 43 文件服务器项目 项目总结与反向代理 7 1 项目总结2 项目提炼3 web服务器的反向代理4 存储节点的反向代理 组件介绍基本写完了 xff0c 后续进行深入 本专栏知识点是通过零声教育的线上课学习 xff0c 进行梳理总结
  • 腾讯云服务器ubuntu18.04搭建FastDFS文件服务器

    腾讯云服务器ubuntu18 04搭建FastDFS文件服务器 FastDFS简介 FastDFS是用c语言编写的一款开源的分布式文件系统 FastDFS为互联网量身定制 充分考虑了冗余备份 负载均衡 线性扩容等机制 并注重高可用 高性能等
  • docker安装fastdfs

    1 搜索fastdfs docker search fastdfs 2 拉取镜像 docker pull morunchang fastdfs 3 运行tracker docker run d name tracker net host m
  • 分布式文件系统 - FastDFS 在UBUNTU下安装

    分布式文件系统 FastDFS 在 CentOS 下配置安装部署 按照该博主的介绍 大部分安装操作正常 只是在创建软连接的时候报错 所以只好用笨办法启动和关闭 启动tracker usr bin fdfs trackerd etc fdfs
  • FastDFS下载文件自定义命名

    上一节我们讲述了FastDFS的搭建和文件的上传 docker搭建FastDFS及遇到的问题解决 花开花落与云卷云舒的博客 CSDN博客 这一节我们讲讲如何将上传的文件下载到我们的本机并还原为原来的文件名 一 前言 在上一节中 我们知道我们
  • 已安装的nginx,添加新模块fastdfs-nginx-module

    1 先看nginx的安装位置和运行目录 不清楚的可以使用命令查看 find name nginx 2 确定安装目录和运行目录后 查看当前nginx的安装路径及已安装的模块等信息 usr local nginx sbin nginx V 3
  • docker安装fastdfs

    一 准备docker环境 二 搜索fastdfs镜像 三 拉取镜像 docker pull delron fastdfs 选取delron fastdfs镜像的原因是包含了nginx不用自己安装nginx转发 也可以选择qbanxiaoli
  • Docker搭建FastDFS

    Docker搭建FastDFS 1 搜索镜像 docker search fastdfs root localhost data docker search fastdfs NAME DESCRIPTION STARS OFFICIAL A
  • fastDFS文件服务器的java客户端初始化方法ClientGlobal.init(fdfs_client.properties) 找不到配置文件路径异常的解决

    最近在使用fastDFS文件服务器的java客户端上传文件时 它的初始化方法ClientGlobal init String 出现找不到配置文件的异常 无论是写死fdfs client properties文件位置还是怎样 都找不到配置文件
  • FastDFS 学习笔记

    一 理论基础 FastDFS比较适合以中小文件为载体的在线服务 比如跟Nginx Apache 配合搭建图片服务器 分布式文件系统FastDFS FastDFS是纯C语言实现 只支持Linux FreeBSD等UNIX系统 FastDFS的
  • FastDFS性能调优 know how

    FastDFS性能调优 本篇文章转载于FastDFS作者 余庆 大佬的 FastDFS分享与交流 公众号 众所周知 软件性能调优不是一撮而就的事情 它是一个反复磨合的过程 下面介绍FastDFS 几个性能调优相关的重要参数 供大家参考 1
  • FastDFS在Docker集群安装

    一 简介 FastDFS是由国人余庆所开发 其项目地址 https github com happyfish100 FastDFS是一个轻量级的开源分布式文件系统 主要解决了大容量的文件存储和高并发访问的问题 文件存取时实现了负载均衡 Fa
  • 使用docker方式安装FastDFS

    FastDFS 架构包括 Tracker server 和 Storage server 客户端请求 Tracker server 进行文件上传 下载 通过 Tracker server 调度 最终由 Storage server 完成文件
  • ubuntu 安装Fastdfs

    安装fastdfs依赖插件libfastcommon 下载 https github com happyfish100 libfastcommon archive V1 0 39 tar gz 创建 usr local software 目
  • FastDFS文件同步机制简介

    FastDFS文件同步机制简介 本篇文章转载于FastDFS作者 余庆 大佬的 FastDFS分享与交流 公众号 FastDFS 文件同步采用 binlog 异步复制方式 storage server 使用 binlog 文件记录文件上传
  • Nginx启动只有master进程而没有worker进程

    大致按照下面文章的提示进行排查 https blog csdn net sinat 37729104 article details 102662475 https blog csdn net qt10086 article details
  • 热敏电阻测温

    热敏电阻器主要分为 PTC 和 NTC 正温度系数热敏电阻器 PTC 在温度越高时电阻值越大 负温度系数热敏电阻器 NTC 在温度越高时电阻值越低 它们同属于半导体器件 测温的热敏电阻一般为NTC 其主要参数有以下几个 标称阻值 标称阻值是
  • fastdfs-client使用教程

    FastDfs客户端使用文档 fastdfs client支持框架 fastdfs client目前支持的框架有springboot1 x springboot2 x springmvc 添加fastdfs client依赖 springb

随机推荐

  • C++ 笔面试知识点大全 附超详细解析 【持续更新中】 (校招/实习/大厂/笔试/面试)

    目录 关键字autodecltypeconststaticexternexplicitvolatileinline Lambda表达式顶层const和底层const类型转换多态 xff0c 虚函数 xff0c 隐藏和重写虚函数的实现机制 x
  • Unity Shader:光照模型,纹理,详细注释

    Phong光照模型 进入摄像机的光线分为四个部分 环境光 xff08 ambient xff09 其他所有间接光照 自发光 xff08 emissive xff09 给定一个方向 xff0c 模型表面本身向该方向发射多少辐射量 漫反射 xf
  • 算法与数据结构 面试知识点大全【持续更新中】(校招/社招/实习/大厂/面试)

    文章目录 排序算法1 冒泡排序2 插入排序3 归并排序4 快速排序5 选择排序 二分搜索1 数组中第k大的数字2 875 爱吃香蕉的珂珂 力扣 xff08 LeetCode xff09 https leetcode cn problems
  • 堆栈

    栈是一种执行 后进先出 算法的数据结构 设想有一个直径不大 一端开口一端封闭的竹筒 有若干个写有编号的小球 xff0c 小球的直径比竹筒的直径略小 现在把不同编号的小球放到竹筒里面 xff0c 可以发现一种规律 xff1a 先放进去的小球只
  • 大端小端和C实现大小端字节序的转化

    大端小端 小端就是低位字节放在内存的低地址端 xff0c 高位字节放在内存的高地址端 大端就是高位字节放在内存的低地址端 xff0c 低位字节放在内存的高地址端 举一个例子 xff0c 比如数字0x12 34 56 78 xff08 注意7
  • 【计算机图形学/实时渲染】 阴影(GAMES202)

    阴影 对于静态的物体 xff0c 可以使用Lightmap烘焙的方法来获取物体的影子 xff08 静态阴影 xff09 xff0c 而对于动态的物体 xff0c 一般采用的是Shadowmap的技术 光照贴图 xff08 Lightmap
  • 解决Mingw-w64下载太慢问题

    官网下载太慢了 xff0c 我们只用换一个镜像源就可以 1 点击Problems Downloading 2 切换香港的
  • 嵌入式Linux开发8——UART串口通讯

    1 背景知识 1 1 UART通讯格式 串口全称叫做串行接口 xff0c 通常也叫做 COM 接口 xff0c 串行接口指的是数据一个一个的顺序传输 xff0c 通信线路简单 使用两条线即可实现双向通信 xff0c 一条用于发送 xff0c
  • 二叉树笔记

    二叉树 二叉搜索 xff08 排序 查找 xff09 树 二叉查找树 xff08 Binary Search Tree xff09 xff0c xff08 又 xff1a 二叉搜索树 xff0c 二叉排序树 xff09 它或者是一棵空树 x
  • C++面试常见题目

    C 43 43 面试常见题目 c 43 43 编译过程自动类型推导auto和decltype重载 重写 xff08 覆盖 xff09 和隐藏的区别C 43 43 构造函数和析构函数能调用虚函数吗volatile关键词运算符重载格式noexe
  • 计算机网络面试常问问题

    C 43 43 面试 计算机网络常见问题 计算机网络常见问题TCP IP协议笔记TCPTCP的特点及目的序列号与确认应答提高可靠性为什么是三次握手和四次挥手滑动窗口流量控制拥塞控制TCP粘包问题 httphttp和https的区别https
  • Trajectory generation for quadrotor while tracking a moving target in cluttered environment

    四旋翼在杂波环境下跟踪运动目标的轨迹生成 摘要1 文章主要贡献2 前言2 1 轨迹公式2 2 实现结构 3 跟踪轨迹生成3 1 标称路径点生成3 2 可行路径点生成3 3 安全飞行走廊生成3 4 代价函数3 5 强制约束3 6 求解跟踪轨迹
  • 翻译-Frustum PointNets for 3D Object Detection from RGB-D Data

    Frustum PointNets for 3D Object Detection from RGB D Data 摘要介绍相关工作从RGB D数据中检测三维物体基于前视图图像的方法 xff1a 基于鸟瞰图的方法 基于3D的方法 点云的深度
  • Online Trajectory Generation of a MAV for Chasing a Moving Target in 3D Dense Environments

    微型无人机的在线轨迹生成 xff0c 用于在3D密集环境中追踪运动目标 摘要一 介绍二 相关工作A 在障碍物环境中追逐B 通过预先规划安全地生成轨迹 三 问题陈述A 问题设置B 能力C 命名 IV 视点生成A 可见度指标B 具有安全性和可见
  • 配置目标跟踪开源项目traj_gen_vis踩过的坑

    项目地址 https github com icsl Jeon traj gen vis 安装依赖需注意的问题 traj gen with qpoases 需安装ros分支的代码 xff08 这个作者并没有指出 xff0c 坑 xff09
  • cmake arm-none-eabi-gcc for stm32 cpp project

    尝试把原有的stm32工程F1canBootloader用cmake来管理 xff0c 遇到了以下几个坑 xff1a 1 报错 xff0c undefined reference to 96 dso handle 39 CMakeFiles
  • 网络攻防之wireshark抓取登录信息

    使用wireshark抓取登录信息 简介 xff1a Wireshark xff08 前称Ethereal xff09 是一个网络封包分析软件 网络封包分析软件的功能是撷取网络封包 xff0c 并尽可能显示出最为详细的网络封包资料 Wire
  • 头文件互相包含所引发的的问题(深入剖析)

    今天写程序出现了一个让人蛋疼的错误 xff0c 后来发现是由于头文件互相包含所引起的 原本只是简单的以为头文件互相包含只会触发 xff0c 头文件的递归包含 即 xff0c A包含B xff0c 所以才A的头文件里会将B的头文件内容拷贝过来
  • C++11异步操作future和aysnc 、function和bind

    C 43 43 11异步操作future和aysnc function和bind 前言异步操作std future和std aysnc 介绍std future和std aysnc的使用Demostd packaged task 介绍std
  • C++文件服务器项目—FastDFS—1

    C 43 43 文件服务器项目 FastDFS 1 前言1 项目架构2 分布式文件系统2 1 传统文件系统2 2 分布式文件系统 3 FastDFS介绍3 1 fdfs概述3 2 fdfs框架中的三个角色3 3 fdfs三个角色之间的关系3