# S1mpleNetDisk **Repository Path**: setekh/s1mple-net-disk ## Basic Information - **Project Name**: S1mpleNetDisk - **Description**: 一个简单的网盘项目~~ - **Primary Language**: C - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 8 - **Forks**: 1 - **Created**: 2024-05-19 - **Last Updated**: 2025-06-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # S1mpleNetDisk —— 一个简单的喵喵网盘 ## 介绍 一个Linux平台下使用C语言实现的简单网盘项目🥳🥳🥳 王道57期百度网盘项目仓库
## 使用说明 ### 运行前需要安装的库 - `yyjson` 静态库已经放置在项目的 `lib` 文件夹内 - 安装 `MySQL` 开发库并自行配置,sql表结构以存放在项目文件夹内 ```bash sudo apt install mysql-server mysql-client sudo apt install libmysqlclient-dev ``` - 安装 `l8w8jwt` 库 - 先下载 `l8w8jwt` 包 https://github.com/GlitchedPolygons/l8w8jwt - 解压到开发环境中 ```bash tar zxvf l8w8jwt-2.1.7-linux-x86_64.tar.gz ``` - 把解压出的文件移动到系统环境中 ```bash 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** ```bash sudo apt-get install doxygen graphviz ``` - 分别生成Client和Server的文档 ```bash doxygen Doxyfile.client doxygen Doxyfile.server ``` - 生成的文档在项目根目录下的`docs`目录中 ## 项目模块划分 ### 服务端模块 - [x] 网络通信 - [x] 建立TCP/IP连接 - [x] 单文件传输 - [X] 文件断点续传 - [x] 文件秒传 - [ ] 客户端断线重连 - [ ] 文件夹下载:递归添加?打包? - [x] 时间轮盘超时踢出 - [ ] 多点下载(仅实现框架,未推送) - [x] 线程池管理 - [x] 线程池的创建、销毁 - [x] 提交任务 - [ ] 动态扩容策略? - [x] 任务队列 - [x] 任务结构体存储函数指针和参数 - [ ] 阻塞队列? - [x] 文件管理 - [x] ~~按用户分配不同的存储路径~~ - [x] 限制用户访问权限 - [x] 哈希值计算 - [x] 数据库 - [x] 虚拟文件森林表 - [x] 用户信息表 - [x] 多线程连接数据库 - [ ] 数据库连接池 - [x] 用户管理 - [x] 用户登录注册验证 - [x] 密码hash+盐值加密验证 - [x] JSON Web Token - [x] 命令解析与执行 - [x] 判断命令合法性 - [x] 常用短命令功能实现 - [ ] 常用短命令接收复杂参数 - [x] 日志记录 - [x] 日志接口函数定义 - [x] 使用线程锁保证线程安全问题 - [x] 日志文件切割与归档 - [ ] 异步日志记录 - [ ] ... ### 客户端模块 - [x] 命令解析 - [x] help辅助命令 - [x] 判断命令合法性 - [x] 登陆注册验证 - [x] 常用短命令功能实现 - [x] 终端界面 - [x] 文件下载进度条(参考apt install) - [x] 可以下载文件的同时输入新的指令? - [x] 其他界面美化(喵娘) - [x] 网络通信 - [x] 与服务端建立TCP连接 - [x] 建立隧道连接 - [x] 文件上传、下载 - [x] 断点续传 - [x] 文件秒传 - [ ] 多点下载 - [x] 文件管理 - [x] 设置下载路径? - [x] 客户端多线程 - [x] 长短指令分离 ## 项目目前存在的问题 - mysql使用存在大量内存泄漏问题,`excutesql()` 函数内部调用了`mysql_store_result()`,该函数会返回查询的结果集,返回result时会申请堆上空间,应当在使用完result后就释放,但是由于项目后期时间紧迫,并未按照严格要求操作,此处需要完善。 - 断点续传在接收端使用mmap优化大文件的处理并没有严格验证,可能存在问题,如文件末尾多余的0的问题。 - 时间紧迫,许多重要函数中存在冗余代码,可能需要优化。 - 由于多线程的原因,只有一个终端界面,下载进度条持续变动时会干扰用户正常输入,目前没有找到好的解决方案。 - 时间轮盘超时踢出的模块存在一个小bug,如果用户在<1s的时间内输入两次命令也会导致踢出 ## 项目临时代码规范 > 一些个人的强迫症罢了🤗 ### 变量命名 - 只使用常见约定俗成的缩写 ```c Queue_t queue_ptr; char buf[1024]; ``` - 变量命名是一般使用**下划线**分隔,包括结构体成员 ```c int net_fd ``` - **描述性信息在前**,变量类型或表示形式在后 ``` c int socket_fd; int epoll_fd; ``` - 结构体类型名使用大驼峰命名 ```c typedef struct pool_s {...} Pool_t; ``` - 类型别名全部使用`_t`结尾 ```c typedef struct thread_pool_s {...} ThreadPool_t; ``` - 必须做重要函数返回值错误判断,且根据具体情况单独做处理,选择返回错误标记还是直接退出,一般不使用ERROR_CHECK宏 ```c ThreadPool_t *pool = (ThreadPool_t *)calloc(1, sizeof(ThreadPool_t)); if (pool == NULL) { return NULL; } ``` - **做错误判断时**接收函数返回值的变量统一使用`ret_`跟函数名或函数名缩写 ```c int ret_send = send(client_socket, buffer, strlen(buffer), 0); ``` - 结构体使用**Doxygen语法**在头文件中注释,结构体用途和成员定义 ```c /** * @brief 服务器配置信息结构体 * 这个结构体用于存储服务器的配置信息,包括端口号、最大连接数和存储路径。 */ typedef struct { int port; /**< 服务器监听的端口号 */ int max_connections; /**< 服务器允许的最大连接数 */ char storage_path[MAX_PATH_LENGTH]; /**< 服务器文件存储路径 */ } ServerConfig; ``` ### 函数命名 - 自定义函数全部使用小驼峰法命名,一般动词开头,后跟多个名词 ```c int sendFile(int net_fd); int initTcpSocket(int * socket_fd, char *ip, char *port); ``` - 使用Doxygen语法在函数对应头文件中注释,表明参数用途、返回值等 ```c /** * @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`,后跟全大写、用下划线分隔的头文件名 ```c #ifndef __LOAD_CONFIG_H #define __LOAD_CONFIG_H ... #endif /* __LOAD_CONFIG_H */ ``` - 源文件内的头文件包含顺序应满足下面的顺序,以确保本模块对应头文件缺失必要头文件时会报错 ```c #include "本模块直接相关的头文件" #include "C库头文件" #include "C++库头文件" #include "其他第三方库头文件" #include "其他项目自定义头文件" ``` - 头文件中仅包含必要的声明和定义,当对应源文件需要引用新的头文件时一般应该在源文件中添加引用 - 头文件应该尽可能自完备,可以独立编译,避免使用前置声明,必要时引用其他头文件 ### Git使用 - 远程仓库使用 master/develop 双分支模式管理项目源码 - 开发不同功能模块时本地应多使用分支以保护主分支通畅 - 本地可使用分支的情况如: - 开发用户登录模块 -> dev-login - 临时修复文件传输bug -> hotfix-transfile - 添加界面美化功能 -> feature-beautify - 推送代码前沟通提交顺序,移除不必要的测试代码尽可能减少冲突 - 永远避免直接在主分支开发代码 - 大版本合并冲突前永远先备份关键代码 ### 其他 - IDE中修改输入制表符时转化为`4`个空格 - 书写函数具体代码时尽可能按照分块逻辑使用空行隔开 - 对于程序执行关键逻辑结点添加必要的日志打印和终端错误提示 - 推送代码前沟通推送顺序,确认分支位置等 - 安装 Error Lens 和 Git Graph 插件 - 未定......