# 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 插件
- 未定......