分布式文件系统 fastdfs 源码分析 之 文件上传流程分析

fastdfs是一个轻量级的分布式文件系统,主要由 tracker server, storage server 以及client组成,这里主要涉及两点 :
1)客户端上传文件流程和协议分析
2)实现一个简单的文件上传函数

一: 文件上传的基本流程

这里写图片描述

fastdfs中上传一个文件,主要涉及以下几个步骤:

1)上传连接请求,客户端会向tracker server发出上传文件的请求
2)tracker收到请求后,返回storage server的ip和端口
3)客户端连接storage,并且上传文件
4)文件上传完成后,storage返回路径信息

以下具体分析文件上传过程中的协议和各种操作

fastdfs协议头部:

typedef struct
    {
        char pkg_len[FDFS_PROTO_PKG_LEN_SIZE];  //body length, not including header(8个字节)
        char cmd;    //command code     TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE
        char status; //status code for response
    } TrackerHeader;

fastdfs协议的头部是由10个字节大小的结构体构成,
发送:发送数据时,先发送TrackerHeader到服务器,随后发送具体的数据
接受:接受数据时,先接受sizeof(TrackerHeader)大小的报文头部,随后接受pkg_len长度的报文体

status: 发送的时候设置为0
cmd: 命令
pkg_len:一个int64_t的整型,除去TrackerHeader长度的报文长度

二: 客户端向tracker server发送获取storage地址请求
#define TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE 101

//            协议头
//            pkg_len | cmd     | status
//            8 bytes | 1 bytes | 1 bytes
//向tracker server请求storage server cmd
#define TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE     101

    TrackerHeader header;//协议头部
    memset(&header, 0, sizeof(TrackerHeader));
    header.cmd = TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE;

    //向tracker server 请求 storage,tcpsenddata 返回非0,表示发送成功
    if(tcpsenddata(sockfd, &header, sizeof(TrackerHeader), 10, &count) != 0)
    {
        fprintf(stderr, "tcpsenddata error: %s\n", strerror(errno));
        return 1;
    }
    else//请求发送成功,等待tracker回复
    {
        //接收头部,头部是一个TrackerHeader类型,10个字节
        TrackerHeader resp;
        if((ret_code = tcprecvdata(sockfd, &resp, sizeof(TrackerHeader), 10, &count)) != 0) 
        {
            fprintf(stderr, "tcprecvdata error: %s\n", strerror(ret_code));
            return 1;
        }
        //开始接收报文体
        //int64_t read_int64(const char *buff)
        //{
   
        //      unsigned char *p;
        //      p = (unsigned char *)buff;
        //      return  (((int64_t)(*p)) << 56) | \
        //      (((int64_t)(*(p+1))) << 48) |  \
        //      (((int64_t)(*(p+2))) << 40) |  \
        //      (((int64_t)(*(p+3))) << 32) |  \
        //      (((int64_t)(*(p+4))) << 24) |  \
        //      (((int64_t)(*(p+5))) << 16) |  \
        //      (((int64_t)(*(p+6))) << 8) | \
        //      ((int64_t)(*(p+7)));
        //}
        int size = read_int64(resp.pkg_len);//获取报体长度
        char *buf = (char*)calloc(size + 1, sizeof(char));

        if((ret_code = tcprecvdata(sockfd, buf, size, 10, &count) != 0)) 
        {
            fprintf(stderr, "tcprecvdata error: %s\n", strerror(ret_code));
            return 1;
        }

        //  报文体
        //  group_name  |ip         |port       |storage_index
        //  16 bytes    |16 bytes   |8 bytes    |
        //#define TRACKER_QUERY_STORAGE_STORE_BODY_LEN 40
        if(count != TRACKER_QUERY_STORAGE_STORE_BODY_LEN)
        {
            fprintf(stderr, "invalid message");
            return 1;
        }
        //group name    
        //#define FDFS_GROUP_NAME_MAX_LEN  16
        char group_name[FDFS_GROUP_NAME_MAX_LEN + 1]  = {
  0};
        memcpy(group_name, buf, FDFS_GROUP_NAME_MAX_LEN);
        group_name[FDFS_GROUP_NAME_MAX_LEN] = '\0';
        //ip: port
        //#define IP_ADDRESS_SIZE 16 
        //port:8 bytes
        char ip[IP_ADDRESS_SIZE + 1] = {
  0};
        memcpy(ip, buf + FDFS_GROUP_NAME_MAX_LEN, IP_ADDRESS_SIZE - 1);
        char szPort[8] = {
  0};
        memcpy(szPort, buf + FDFS_GROUP_NAME_MAX_LEN + IP_ADDRESS_SIZE - 1, 8);
        ip[IP_ADDRESS_SIZE] = '\0';
        int port = read_int64(szPort);
        //storage index;
        char *storage_index = buf + FDFS_GROUP_NAME_MAX_LEN + IP_ADDRESS_SIZE - 1 + FDFS_PROTO_PKG_LEN_SIZE;

三:以上步骤完成后,获取storage的ip 和 port后,就可以上传文件了

在官方的客户端中,文件操作有upload,download, append,delete等,这里只涉及upload
上传文件中,官方给出了三种方式
1)通过buffer上传,即将文件读取进内存,然后在发送
2)使用sendfile,sendfile是Linux提供的一个库函数
3)通过回调函数的方式

这里主要涉及的是第一种,通过buffer上传的方式

文件上传协议:

//文件上传协议头部
    10 bytes        | 1 bytes        | 8 bytes    | 6 bytes        |
    TrackerHeader   | storage_index  | 文件长度    | 文件名或者全为0)  |
//storage_index 是客户端向tracker server申请storage index时候返回的结果
//文件名 如果不为空,那么取前6位,或者可以全部设置为0



//上传完成 storage回复客户端协议
10 bytes      | 16 bytes    | TrackerHeader.pkg_len - 16bytes 
TrackerHeader | groupname   | remote fi
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值