S1mple-NetDisk

仓库链接
https://gitee.com/setekh/s1mple-net-disk

介绍

一个Linux平台下使用C语言实现的简单网盘项目🥳🥳🥳

使用说明

运行前需要安装的库

  • yyjson 静态库已经放置在项目的 lib 文件夹内
  • 安装 MySQL 开发库并自行配置,sql表结构以存放在项目文件夹内
    sudo apt install mysql-server mysql-client
    sudo apt install libmysqlclient-dev
  • 安装 l8w8jwt
    tar zxvf l8w8jwt-2.1.7-linux-x86_64.tar.gz
    • 把解压出的文件移动到系统环境中
    sudo cp -r l8w8jwt/include/l8w8jwt/ /usr/include/
    sudo cp l8w8jwt/bin/release/* /usr/lib
    • 使用时引用 l8w8jwt 相应的头文件,在Makefile中增加编译链接 -ll8w8jwt

服务端使用

  • config/server_config.json 中修改ip和端口配置
  • 确保你的 server 文件夹下有以下目录
    • config 配置文件
    • include 头文件
    • lib 第三方静态库文件
    • log 服务器日志
    • obj 编译过程生成的目标文件
    • src 源文件
    • storage 服务器存储文件的真实目录
  • 服务端可使用 shutdown 指令有序退出

客户端使用

  • 确保你的 client 文件夹下有以下目录
    • include 头文件
    • obj 编译过程生成的目标文件
    • src 源文件 
    • storage 客户端用于存储下载文件的目录
  • 可用指令列表如下
    • login : 用于登录到系统。使用方法: login
    • signup : 用于注册新用户。使用方法: signup
    • quit : 退出程序。使用方法: quit
    • help : 显示帮助信息。使用方法: help <命令>
    • ls : 列出当前目录下的文件和文件夹。使用方法: ls
    • ll : 列出当前目录下的文件和文件夹的详细信息。使用方法: ll
    • cd : 切换目录。使用方法: cd <目录路径>
    • pwd : 显示当前所在目录。使用方法: pwd
    • remove : 删除文件或文件夹。使用方法: remove <文件或文件夹路径> (删除文件夹是末尾需要加上/)
    • mv : 移动文件或文件夹。使用方法: mv <源路径> <目标路径>
    • mkdir : 创建新目录。使用方法: mkdir <目录路径>
    • download : 下载文件。使用方法: download <远程文件路径> <本地保存路径>
    • upload : 上传文件。使用方法: upload <本地文件路径> <远程保存路径>
    • multiget : 多点下载,未完全实现

Doxygen文档生成

  • 使用了自定义主题 doxygen-awesome-css
    🥰 https://github.com/jothepro/doxygen-awesome-css
  • 生成引用关系图、函数调用关系图等需要额外安装 graphviz
    sudo apt-get install doxygen graphviz
  • 分别生成Client和Server的文档
    doxygen Doxyfile.client
    doxygen Doxyfile.server
  • 生成的文档在项目根目录下的docs目录中

项目模块划分

服务端模块

  • 网络通信
    • 建立TCP/IP连接
    • 单文件传输
    • 文件断点续传
    • 文件秒传
    • 客户端断线重连
    • 文件夹下载:递归添加?打包?
    • 时间轮盘超时踢出
    • 多点下载(仅实现框架,未推送)
  • 线程池管理
    • 线程池的创建、销毁
    • 提交任务
    • 动态扩容策略?
  • 任务队列
    • 任务结构体存储函数指针和参数
    • 阻塞队列?
  • 文件管理
    • 按用户分配不同的存储路径
    • 限制用户访问权限
    • 哈希值计算
  • 数据库
    • 虚拟文件森林表
    • 用户信息表
    • 多线程连接数据库
    • 数据库连接池
  • 用户管理
    • 用户登录注册验证
    • 密码hash+盐值加密验证
    • JSON Web Token
  • 命令解析与执行
    • 判断命令合法性
    • 常用短命令功能实现
    • 常用短命令接收复杂参数
  • 日志记录
    • 日志接口函数定义
    • 使用线程锁保证线程安全问题
    • 日志文件切割与归档
    • 异步日志记录
  • ...

客户端模块

  • 命令解析
    • help辅助命令
    • 判断命令合法性
    • 登陆注册验证
    • 常用短命令功能实现
  • 终端界面
    • 文件下载进度条(参考apt install)
    • 可以下载文件的同时输入新的指令?
    • 其他界面美化(喵娘)
  • 网络通信
    • 与服务端建立TCP连接
    • 建立隧道连接
    • 文件上传、下载
    • 断点续传
    • 文件秒传
    • 多点下载
  • 文件管理
    • 设置下载路径?
  • 客户端多线程
    • 长短指令分离

项目临时代码规范

一些个人的强迫症罢了🤗

变量命名

  • 只使用常见约定俗成的缩写
    Queue_t queue_ptr;
    char buf[1024];
  • 变量命名是一般使用下划线分隔,包括结构体成员
    int net_fd
  • 描述性信息在前,变量类型或表示形式在后
    int socket_fd;
    int epoll_fd;
  • 结构体类型名使用大驼峰命名
    typedef struct pool_s {...} Pool_t;
  • 类型别名全部使用_t结尾
    typedef struct thread_pool_s {...} ThreadPool_t;
  • 必须做重要函数返回值错误判断,且根据具体情况单独做处理,选择返回错误标记还是直接退出,一般不使用ERROR_CHECK宏
    ThreadPool_t *pool = (ThreadPool_t *)calloc(1, sizeof(ThreadPool_t));
    if (pool == NULL)
    {
      return NULL;
    }
  • 做错误判断时接收函数返回值的变量统一使用ret_跟函数名或函数名缩写
    int ret_send = send(client_socket, buffer, strlen(buffer), 0);
  • 结构体使用Doxygen语法在头文件中注释,结构体用途和成员定义
    /**
    * @brief 服务器配置信息结构体
    * 这个结构体用于存储服务器的配置信息,包括端口号、最大连接数和存储路径。
    */
    typedef struct
    {
      int port; /**< 服务器监听的端口号 */
      int max_connections; /**< 服务器允许的最大连接数 */
      char storage_path[MAX_PATH_LENGTH]; /**< 服务器文件存储路径 */
    } ServerConfig;

函数命名

  • 自定义函数全部使用小驼峰法命名,一般动词开头,后跟多个名词
    int sendFile(int net_fd);
    int initTcpSocket(int * socket_fd, char *ip, char *port);
  • 使用Doxygen语法在函数对应头文件中注释,表明参数用途、返回值等
    /**
    * @brief 从配置文件中加载服务器配置信息
    * 从指定路径的配置文件中读取服务器的配置信息,并将其加载到指定的服务器配置结构体中。
    * @param file_path 配置文件的路径
    * @param config 指向服务器配置结构体的指针,用于存储加载的配置信息
    * @return
    */
    void loadServerConfig(const char *file_path, ServerConfig_t *config);

文件命名

  • 全部使用小写字母和下划线
    server.c
    tcp_init.c
    thread_pool.c

头文件与源文件

  • 头文件保护语法全部使用 #ifndef,后跟全大写、用下划线分隔的头文件名
    #ifndef __LOAD_CONFIG_H
    #define __LOAD_CONFIG_H
    ...
    #endif /* __LOAD_CONFIG_H */
  • 源文件内的头文件包含顺序应满足下面的顺序,以确保本模块对应头文件缺失必要头文件时会报错
    #include "本模块直接相关的头文件"
    
    #include "C库头文件"
    
    #include "C++库头文件"
    
    #include "其他第三方库头文件"
    
    #include "其他项目自定义头文件"
  • 头文件中仅包含必要的声明和定义,当对应源文件需要引用新的头文件时一般应该在源文件中添加引用
  • 头文件应该尽可能自完备,可以独立编译,避免使用前置声明,必要时引用其他头文件

Git使用

  • 远程仓库使用 master/develop 双分支模式管理项目源码
  • 开发不同功能模块时本地应多使用分支以保护主分支通畅
  • 本地可使用分支的情况如:
    • 开发用户登录模块 -> dev-login
    • 临时修复文件传输bug -> hotfix-transfile
    • 添加界面美化功能 -> feature-beautify
  • 推送代码前沟通提交顺序,移除不必要的测试代码尽可能减少冲突
  • 永远避免直接在主分支开发代码
  • 大版本合并冲突前永远先备份关键代码

其他

  • IDE中修改输入制表符时转化为4个空格
  • 书写函数具体代码时尽可能按照分块逻辑使用空行隔开
  • 对于程序执行关键逻辑结点添加必要的日志打印和终端错误提示
  • 推送代码前沟通推送顺序,确认分支位置等
  • 安装 Error Lens 和 Git Graph 插件
  • 未定......
(❁´◡`❁)编程笨蛋萌新也想折腾博客!
最后更新于 2024-06-01