feat:功能完成

This commit is contained in:
tomyee 2024-12-18 17:24:29 +08:00
parent 1cee5d570f
commit 1de826649b
45 changed files with 416 additions and 1938 deletions

1
.gitignore vendored
View File

@ -52,3 +52,4 @@
./files/*
./newfile/*
./test/*

File diff suppressed because it is too large Load Diff

BIN
client

Binary file not shown.

View File

@ -13,10 +13,9 @@
void upload_file(int client_socket)
{
//发送通知服务器是上传文件
// 发送通知服务器是上传文件
send(client_socket, "upload", strlen("upload"), 0);
char file_name[BUFFER_SIZE];
char file_content[BUFFER_SIZE];
mkdir("./newfile", 0777);
@ -39,11 +38,6 @@ void upload_file(int client_socket)
}
printf("文件名部分是: %s\n", base_name);
// 用户输入文件内容
printf("输入文件内容(输入完毕后按回车结束):\n");
getchar(); // 清除上一次输入的换行符
fgets(file_content, BUFFER_SIZE, stdin);
char dir_name[256];
snprintf(dir_name, 256, "./newfile/%s", file_name);
printf("文件路径是: %s\n", dir_name);
@ -55,6 +49,18 @@ void upload_file(int client_socket)
perror("文件创建失败");
return;
}
// 用户输入文件内容
printf("请输入文件内容,输入 EOF 表示结束:\n");
getchar(); // 清除上一次输入的换行符
while (fgets(file_content, sizeof(file_content), stdin))
{
if (strcmp(file_content, "EOF\n") == 0)
{
break;
}
fputs(file_content, plain_file);
}
fprintf(plain_file, "%s", file_content);
fclose(plain_file);
printf("文件创建成功,准备上传。\n");
@ -73,23 +79,35 @@ void upload_file(int client_socket)
printf("服务端未确认文件名。\n");
return;
}
// 发送文件内容到服务器
FILE *file = fopen(file_name, "rb");
FILE *file = fopen(dir_name, "r");
if (!file)
{
perror("文件打开失败");
close(client_socket);
return;
}
// char buffer[BUFFER_SIZE];
// int bytes_read;
// // 分块读取文件内容并发送到服务端
// while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, file)) > 0)
// {
// if (send(client_socket, buffer, bytes_read, 0) < 0)
// {
// perror("发送文件数据失败");
// fclose(file);
// return;
// }
// }
// 发送文件内容
char buffer[BUFFER_SIZE];
int bytes_read;
// 分块读取文件内容并发送到服务端
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, file)) > 0)
while (!feof(file))
{
if (send(client_socket, buffer, bytes_read, 0) < 0)
int bytes_read = fread(buffer, 1, BUFFER_SIZE, file);
if (bytes_read > 0)
{
perror("发送文件数据失败");
fclose(file);
return;
send(client_socket, buffer, bytes_read, 0);
}
}
fclose(file);
@ -99,24 +117,27 @@ void upload_file(int client_socket)
// 等待服务器发送加密压缩包的路径
char compressed_path[BUFFER_SIZE] = {0};
ssize_t bytes_received = read(client_socket, compressed_path, BUFFER_SIZE - 1);
if (bytes_received > 0) {
compressed_path[bytes_received] = '\0'; // 确保字符串以空字符结尾
if (bytes_received > 0)
{
compressed_path[bytes_received] = '\0'; // 确保字符串以空字符结尾
printf("服务器发送的加密压缩包路径是: %s\n", compressed_path);
} else {
}
else
{
perror("读取服务器发送的路径失败");
}
}
void download_file(int client_socket)
{
// 发送通知服务器是下载文件
send(client_socket, "download", strlen("download"), 0);
char output_file_name[BUFFER_SIZE];
char file_path[BUFFER_SIZE];
printf("输入要下载的文件(加密后的文件压缩包)完整路径: ");
scanf("%s", file_path);
// 发送下载请求到服务器
send(client_socket, "download", strlen("download"), 0);
send(client_socket, file_path, strlen(file_path), 0);
// 等待服务端准备完成的信号
char ack[BUFFER_SIZE] = {0};
@ -144,6 +165,14 @@ void download_file(int client_socket)
int bytes_read;
while ((bytes_read = read(client_socket, buffer, BUFFER_SIZE)) > 0)
{
// 检查是否包含结束标志
if (strstr(buffer, "stop") != NULL)
{
fwrite(buffer, 1, bytes_read - strlen("stop"), output); // 写入实际数据
break;
}
fwrite(buffer, 1, bytes_read, output);
printf("接收到 %d 字节数据。\n", bytes_read);
fwrite(buffer, 1, bytes_read, output);
}
fclose(output);

View File

@ -0,0 +1 @@
ùê‰ç‡¥on#˜ZhiT¯

BIN
files/20241218160257/abc.gz Normal file

Binary file not shown.

View File

@ -1 +1,2 @@
123
EOF

View File

@ -0,0 +1 @@
!e;`žSCÿCŠ·î¦

Binary file not shown.

View File

@ -0,0 +1,2 @@
jkflsdj
EOF

View File

@ -0,0 +1 @@
я€¦ґGЫ©^µ±И† †

BIN
files/20241218171517/123.gz Normal file

Binary file not shown.

View File

@ -0,0 +1,2 @@
fdjksalfj
EOF

View File

@ -0,0 +1 @@
 :(°W¸@BăĂý

BIN
files/20241218171921/345.gz Normal file

Binary file not shown.

View File

@ -0,0 +1,2 @@
123
EOF

1
files/decrypt/123.enc Normal file
View File

@ -0,0 +1 @@
я€¦ґGЫ©^µ±И† †

2
files/decrypt/123.txt Normal file
View File

@ -0,0 +1,2 @@
fdjksalfj
EOF

1
files/decrypt/345.enc Normal file
View File

@ -0,0 +1 @@
 :(°W¸@BăĂý

2
files/decrypt/345.txt Normal file
View File

@ -0,0 +1,2 @@
123
EOF

1
files/decrypt/test.enc Normal file
View File

@ -0,0 +1 @@
!e;`žSCÿCŠ·î¦

View File

@ -1 +1,2 @@
123
fdjksalfj
EOF

View File

@ -1 +0,0 @@
1233

View File

@ -1 +0,0 @@
1234

2
newfile/345.txt Normal file
View File

@ -0,0 +1,2 @@
123
EOF

2
newfile/abc.txt Normal file
View File

@ -0,0 +1,2 @@
123
EOF

2
newfile/test.txt Normal file
View File

@ -0,0 +1,2 @@
jkflsdj
EOF

2
output.txt Normal file
View File

@ -0,0 +1,2 @@
123
EOF

BIN
server

Binary file not shown.

285
server.c
View File

@ -166,7 +166,7 @@ int sm4_cbc_padding_decrypt_file(const char *input_file, const char *output_file
// 最后一块,带填充解密
if (sm4_cbc_padding_decrypt(&dec_key, iv, input_block, bytes_read, output_block, &outlen) != 1)
{
fprintf(stderr, "解密失败。\n");
fprintf(stderr, "带填充解密解密失败。\n");
fclose(in_file);
fclose(out_file);
return 0;
@ -177,7 +177,7 @@ int sm4_cbc_padding_decrypt_file(const char *input_file, const char *output_file
// 中间块,不需要处理填充
if (sm4_cbc_padding_decrypt(&dec_key, iv, input_block, bytes_read, output_block, &outlen) != 1)
{
fprintf(stderr, "解密失败。\n");
fprintf(stderr, "不需要处理填充解密失败。\n");
fclose(in_file);
fclose(out_file);
return 0;
@ -191,6 +191,40 @@ int sm4_cbc_padding_decrypt_file(const char *input_file, const char *output_file
return 1; // 成功
}
void extract_path_and_filename(const char *input, char *path, char *filename) {
int last_slash_index = -1; // 记录最后一个 '/' 的位置
int last_dot_index = -1; // 记录最后一个 '.' 的位置
// 遍历路径字符串,找到最后一个 '/' 和 '.'
for (int i = 0; input[i] != '\0'; i++) {
if (input[i] == '/') {
last_slash_index = i; // 更新最后一个 '/' 的位置
}
if (input[i] == '.') {
last_dot_index = i; // 更新最后一个 '.' 的位置
}
}
// 提取路径部分(从开头到最后一个 '/'
if (last_slash_index != -1) {
strncpy(path, input, last_slash_index + 1);
path[last_slash_index + 1] = '\0'; // 确保路径部分以 '\0' 结尾
} else {
path[0] = '\0'; // 如果没有 '/', 为空
}
// 如果 '.' 在 '/' 之前或没有 '.', 忽略后缀处理
if (last_dot_index <= last_slash_index) {
last_dot_index = -1;
}
// 提取文件名部分(从最后一个 '/' 到最后一个 '.' 之间)
int j = 0; // 文件名的索引
for (int i = last_slash_index + 1; i < (last_dot_index == -1 ? strlen(input) : last_dot_index); i++) {
filename[j++] = input[i];
}
filename[j] = '\0'; // 添加字符串结束符
}
// 客户端处理线程
void *client_handler(void *arg)
{
@ -198,148 +232,161 @@ void *client_handler(void *arg)
free(arg);
char buffer[BUFFER_SIZE];
// 初始化缓冲区为 0
memset(buffer, 0, BUFFER_SIZE);
// 接收第一个参数判断参数客户端需要上传还是下载
int bytes = read(client_socket, buffer, BUFFER_SIZE - 1);// 预留一个字节用于NULL终止符
if (bytes <= 0)
while (1)
{
perror("接收客户端命令失败");
return NULL;
}
buffer[bytes] = '\0'; // 确保以 NULL 结尾
char upload_or_download[256] ;
snprintf(upload_or_download, sizeof(upload_or_download), "%s", buffer);
printf("客户端发起请求:%s,等待后续指令....\n", upload_or_download);
char origin_file_path[256], dir_name[128], file_path[256], compressed_file[256], decrypted_file[256];
if (strcmp(upload_or_download, "upload") == 0)
{
// 接收文件名(不含后缀)
int bytes = read(client_socket, buffer, BUFFER_SIZE);
printf("等待客户端发送命令中...\n");
// 初始化缓冲区为 0
memset(buffer, 0, BUFFER_SIZE);
// 接收第一个参数判断参数客户端需要上传还是下载
int bytes = read(client_socket, buffer, BUFFER_SIZE - 1); // 预留一个字节用于NULL终止符
if (bytes <= 0)
{
perror("接收文件名失败");
return NULL;
perror("接收客户端命令失败");
break; // 如果读取失败或连接关闭,退出循环
}
buffer[bytes] = '\0'; // 确保以 NULL 结尾
char file_name[256];
snprintf(file_name, sizeof(file_name), "%s", buffer);
printf("接收文件名:%s\n", file_name);
// 发送 ACK 确认
send(client_socket, "ACK", strlen("ACK"), 0);
char upload_or_download[256];
snprintf(upload_or_download, sizeof(upload_or_download), "%s", buffer);
printf("客户端发起请求:%s, 等待后续指令....\n", upload_or_download);
// 先生成./files目录再生成时间戳目录调用 create_timestamp_dir 函数,生成一个基于时间戳的目录名称,并将其存储在 dir_name 中
create_timestamp_dir(dir_name);
char origin_file_path[256], dir_name[128], file_path[256], compressed_file[256], decrypted_file[256];
// 根据传入的文件名以及时间戳拼接生成源文件路径
sprintf(origin_file_path, "%s/%s.txt", dir_name, buffer);
// 加密后的文件路径
sprintf(file_path, "%s/%s.enc", dir_name, buffer);
// 加密后压缩包的文件路径
sprintf(compressed_file, "%s/%s.gz", dir_name, buffer);
// 解密的文件路径
snprintf(decrypted_file, sizeof(decrypted_file), "./files/decrypt/%s_decrypted.txt", buffer);
printf("源文件路径:%s\n加密后的文件:%s\n压缩的文件:%s\n解密的文件路径:%s\n", origin_file_path, file_path, compressed_file, decrypted_file);
FILE *file = fopen(origin_file_path, "wb");
if (!file)
if (strcmp(upload_or_download, "upload") == 0)
{
perror("文件打开失败");
return NULL;
}
// 按块读取源文件内容并保存到origin_file_path
while (1)
{
int bytes = read(client_socket, buffer, BUFFER_SIZE -1);
if (bytes < 0)
// 接收文件名(不含后缀)
int bytes = read(client_socket, buffer, BUFFER_SIZE);
if (bytes <= 0)
{
perror("读取数据失败");
fclose(file);
perror("接收文件名失败");
return NULL;
}
// 检测是否接收到结束标志
if (strncmp(buffer, "EOF", 3) == 0)
break;
// 将数据写入文件
if (fwrite(buffer, 1, bytes, file) != bytes)
buffer[bytes] = '\0'; // 确保以 NULL 结尾
char file_name[256];
snprintf(file_name, sizeof(file_name), "%s", buffer);
printf("接收文件名:%s\n", file_name);
// 发送 ACK 确认
send(client_socket, "ACK", strlen("ACK"), 0);
// 先生成./files目录再生成时间戳目录调用 create_timestamp_dir 函数,生成一个基于时间戳的目录名称,并将其存储在 dir_name 中
create_timestamp_dir(dir_name);
// 根据传入的文件名以及时间戳拼接生成源文件路径
sprintf(origin_file_path, "%s/%s.txt", dir_name, buffer);
// 加密后的文件路径
sprintf(file_path, "%s/%s.enc", dir_name, buffer);
// 加密后压缩包的文件路径
sprintf(compressed_file, "%s/%s.gz", dir_name, buffer);
// 解密的文件路径
snprintf(decrypted_file, sizeof(decrypted_file), "./files/decrypt/%s_decrypted.txt", buffer);
printf("源文件路径:%s\n加密后的文件:%s\n压缩的文件:%s\n解密的文件路径:%s\n", origin_file_path, file_path, compressed_file, decrypted_file);
FILE *file = fopen(origin_file_path, "w");
if (!file)
{
perror("写入文件失败");
fclose(file);
perror("文件打开失败");
return NULL;
}
// 接收分块数据
int bytes_received;
while ((bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0)) > 0)
{
// 检查是否包含结束标志
if (strstr(buffer, "EOF") != NULL)
{
fwrite(buffer, 1, bytes_received - strlen("EOF"), file); // 写入实际数据
break;
}
fwrite(buffer, 1, bytes_received, file);
printf("接收到 %d 字节数据。\n", bytes_received);
}
fclose(file);
log_operation("文件已接收。\n");
// 加密文件
printf("正在加密文件...\n");
sm4_cbc_padding_encrypt_file(origin_file_path, file_path, key, iv);
printf("文件加密完成。\n");
char log_message_file_path[BUFFER_SIZE];
sprintf(log_message_file_path, "文件已加密。加密文件保存路径为:%s\n", file_path);
log_operation(log_message_file_path);
// 压缩文件
printf("正在压缩被加密的文件...\n");
compress_file(file_path, compressed_file);
printf("文件压缩完成。\n");
// 删除加密文件
// remove(file_path);
char log_message_compressed_file[BUFFER_SIZE];
sprintf(log_message_compressed_file, "文件已加密。加密文件保存路径为:%s\n", compressed_file);
// 发送压缩的加密文件路径给客户端
send(client_socket, compressed_file, strlen(compressed_file), 0);
log_operation(log_message_compressed_file);
}
fclose(file);
log_operation("文件已接收。\n");
// 加密文件
printf("正在加密文件...\n");
sm4_cbc_padding_encrypt_file(origin_file_path, file_path, key, iv);
printf("文件加密完成。\n");
char log_message_file_path[BUFFER_SIZE];
sprintf(log_message_file_path, "文件已加密。加密文件保存路径为:%s\n", file_path);
log_operation(log_message_file_path);
// 压缩文件
printf("正在压缩被加密的文件...\n");
compress_file(file_path, compressed_file);
printf("文件压缩完成。\n");
// 删除加密文件
// remove(file_path);
char log_message_compressed_file[BUFFER_SIZE];
sprintf(log_message_compressed_file, "文件已加密。加密文件保存路径为:%s\n", compressed_file);
// 发送压缩的加密文件路径给客户端
send(client_socket, compressed_file, strlen(compressed_file), 0);
log_operation(log_message_compressed_file);
}
else if (strcmp(upload_or_download, "download") == 0)
{
printf("接收到下载请求...\n");
memset(buffer, 0, BUFFER_SIZE);
// 读取文件路径
read(client_socket, buffer, BUFFER_SIZE);
sprintf(compressed_file, "%s", buffer);
// 解压缩、解密并发送给客户端
decompress_file(compressed_file, compressed_file);
printf("文件解压缩完成。\n");
printf("正在解密文件...\n");
sm4_cbc_padding_decrypt_file(decrypted_file, decrypted_file, key, iv);
printf("文件解密完成。\n");
log_operation("文件已解压并解密,准备发送。\n");
// 向客户端发送 "READY" 信号
send(client_socket, "READY", strlen("READY"), 0);
// 发送解密后的文件
FILE *file_to_send = fopen(decrypted_file, "rb");
while (!feof(file_to_send))
else if (strcmp(upload_or_download, "download") == 0)
{
int bytes_read = fread(buffer, 1, BUFFER_SIZE, file_to_send);
send(client_socket, buffer, bytes_read, 0);
}
fclose(file_to_send);
printf("接收到下载请求...\n");
printf("文件发送完成。\n");
// 删除解密后的文件
// remove(decrypted_file);
}
else
{
perror("读取客户端命令失败");
memset(buffer, 0, BUFFER_SIZE);
// 读取文件路径
read(client_socket, buffer, BUFFER_SIZE);
char path[256]; // 存储提取的路径(无后缀)
char filename[256]; // 存储提取的文件名
extract_path_and_filename(buffer, path, filename);
//压缩包路径
sprintf(compressed_file, "%s", buffer);
// 解压后的加密文件路径
sprintf(file_path, "./files/decrypt/%s.enc",filename);
// 解密文件路径
sprintf(decrypted_file, "./files/decrypt/%s.txt", filename);
printf("%s\n", compressed_file);
printf("%s\n", file_path);
printf("%s\n", decrypted_file);
// 解压缩、解密并发送给客户端
decompress_file(compressed_file, file_path);
printf("文件解压缩完成。\n");
printf("正在解密文件...\n");
sm4_cbc_padding_decrypt_file(file_path, decrypted_file, key, iv);
printf("文件解密完成。\n");
log_operation("文件已解压并解密,准备发送。\n");
// 向客户端发送 "READY" 信号
send(client_socket, "READY", strlen("READY"), 0);
// 发送解密后的文件
FILE *file_to_send = fopen(decrypted_file, "rb");
while (!feof(file_to_send))
{
int bytes_read = fread(buffer, 1, BUFFER_SIZE, file_to_send);
send(client_socket, buffer, bytes_read, 0);
}
fclose(file_to_send);
printf("文件发送完成。\n");
// 向客户端发送 "READY" 信号
send(client_socket, "stop", strlen("stop"), 0);
// 删除解密后的文件
// remove(decrypted_file);
}
else
{
perror("读取客户端命令失败");
break;
}
memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区,准备接收下一个命令
}
// 关闭连接
close(client_socket);
dispatch_semaphore_signal(semaphore);
return NULL;
}
int main()
{

BIN
test/client Executable file

Binary file not shown.

80
test/client.c Normal file
View File

@ -0,0 +1,80 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8002
#define BUFFER_SIZE 1024
int main() {
int client_socket;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
char filename[100];
// 创建客户端 socket
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1) {
perror("客户端 socket 创建失败");
exit(EXIT_FAILURE);
}
// 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
// 连接到服务器
if (connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("连接服务器失败");
close(client_socket);
exit(EXIT_FAILURE);
}
printf("连接服务器成功!\n");
// 输入文件名并创建文件
printf("请输入要创建的文件名(例如 output.txt");
fgets(filename, sizeof(filename), stdin);
filename[strcspn(filename, "\n")] = 0; // 去掉换行符
FILE *file = fopen(filename, "w");
if (!file) {
perror("文件创建失败");
close(client_socket);
exit(EXIT_FAILURE);
}
printf("请输入文件内容,输入 EOF 表示结束:\n");
while (fgets(buffer, sizeof(buffer), stdin)) {
if (strcmp(buffer, "EOF\n") == 0) {
break;
}
fputs(buffer, file);
}
fclose(file);
// 重新打开文件以读取并发送给服务器
file = fopen(filename, "r");
if (!file) {
perror("文件打开失败");
close(client_socket);
exit(EXIT_FAILURE);
}
// 分块发送文件内容
int bytes_read;
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, file)) > 0) {
send(client_socket, buffer, bytes_read, 0);
printf("发送 %d 字节数据。\n", bytes_read);
}
printf("文件内容已发送到服务器。\n");
// 关闭文件和 socket
fclose(file);
close(client_socket);
return 0;
}

View File

1
test/received_file.txt Normal file
View File

@ -0,0 +1 @@
jfkdlsajfkalEOF

BIN
test/server Executable file

Binary file not shown.

85
test/server.c Normal file
View File

@ -0,0 +1,85 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8002
#define BUFFER_SIZE 1024
int main() {
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
char buffer[BUFFER_SIZE];
socklen_t client_addr_len = sizeof(client_addr);
// 创建服务器 socket
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("服务器 socket 创建失败");
exit(EXIT_FAILURE);
}
// 设置 SO_REUSEADDR
int opt = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
perror("设置 SO_REUSEADDR 失败");
exit(EXIT_FAILURE);
}
// 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// 绑定服务器 socket
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("绑定失败");
close(server_socket);
exit(EXIT_FAILURE);
}
// 开始监听
if (listen(server_socket, 5) == -1) {
perror("监听失败");
close(server_socket);
exit(EXIT_FAILURE);
}
printf("服务器已启动,等待客户端连接...\n");
// 接受客户端连接
client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len);
if (client_socket == -1) {
perror("接受客户端连接失败");
close(server_socket);
exit(EXIT_FAILURE);
}
printf("客户端连接成功。\n");
// 打开文件以写入接收到的数据
FILE *file = fopen("received_file.txt", "w");
if (!file) {
perror("文件打开失败");
close(client_socket);
close(server_socket);
exit(EXIT_FAILURE);
}
// 接收分块数据
int bytes_received;
while ((bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0)) > 0) {
fwrite(buffer, 1, bytes_received, file);
printf("接收到 %d 字节数据。\n", bytes_received);
}
printf("文件接收完成,已保存为 received_file.txt\n");
// 关闭文件和 socket
fclose(file);
close(client_socket);
close(server_socket);
return 0;
}

1
test/test.txt Normal file
View File

@ -0,0 +1 @@
jfkdlsajfkalEOF