From d5eba67d09328a27c483f99cb27ea08e2d713056 Mon Sep 17 00:00:00 2001 From: zibright Date: Tue, 10 Jun 2025 23:43:56 +0800 Subject: [PATCH] add all --- Clion/.idea/.gitignore | 8 + Clion/.idea/Clion.iml | 2 + Clion/.idea/editor.xml | 251 ++++++++++++++ Clion/.idea/misc.xml | 8 + Clion/.idea/modules.xml | 8 + Clion/.idea/vcs.xml | 6 + Clion/CMakeLists.txt | 6 + Clion/main.c | 7 + Clion/test.c | 10 + Clion/test.exe | Bin 0 -> 80466 bytes Code/Project_Client.c | 0 Code/Project_Server.c | 0 Code/cet.c | 54 +++ Code/output/cet | Bin 0 -> 16400 bytes Code/ser.c | 65 ++++ Project/client | Bin 0 -> 17264 bytes Project/client.c | 270 +++++++++++++++ Project/server | Bin 0 -> 26032 bytes Project/server.c | 471 ++++++++++++++++++++++++++ Project/test/Client.c | 422 +++++++++++++++++++++++ Project/test/Server.c | 517 +++++++++++++++++++++++++++++ Project/test/client | Bin 0 -> 22048 bytes Project/test/server | Bin 0 -> 26080 bytes Project/users.txt | 1 + Project/新建文件夹/Client_Cursor.c | 108 ++++++ Project/新建文件夹/Server_Cursor.c | 138 ++++++++ Project/新建文件夹/User.c | 94 ++++++ Project/新建文件夹/User.h | 21 ++ Project/新建文件夹/protocol.h | 22 ++ Project/新建文件夹/users.txt | 1 + 30 files changed, 2490 insertions(+) create mode 100644 Clion/.idea/.gitignore create mode 100644 Clion/.idea/Clion.iml create mode 100644 Clion/.idea/editor.xml create mode 100644 Clion/.idea/misc.xml create mode 100644 Clion/.idea/modules.xml create mode 100644 Clion/.idea/vcs.xml create mode 100644 Clion/CMakeLists.txt create mode 100644 Clion/main.c create mode 100644 Clion/test.c create mode 100644 Clion/test.exe create mode 100644 Code/Project_Client.c create mode 100644 Code/Project_Server.c create mode 100644 Code/cet.c create mode 100644 Code/output/cet create mode 100644 Code/ser.c create mode 100644 Project/client create mode 100644 Project/client.c create mode 100644 Project/server create mode 100644 Project/server.c create mode 100644 Project/test/Client.c create mode 100644 Project/test/Server.c create mode 100644 Project/test/client create mode 100644 Project/test/server create mode 100644 Project/users.txt create mode 100644 Project/新建文件夹/Client_Cursor.c create mode 100644 Project/新建文件夹/Server_Cursor.c create mode 100644 Project/新建文件夹/User.c create mode 100644 Project/新建文件夹/User.h create mode 100644 Project/新建文件夹/protocol.h create mode 100644 Project/新建文件夹/users.txt diff --git a/Clion/.idea/.gitignore b/Clion/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/Clion/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/Clion/.idea/Clion.iml b/Clion/.idea/Clion.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/Clion/.idea/Clion.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Clion/.idea/editor.xml b/Clion/.idea/editor.xml new file mode 100644 index 0000000..633b554 --- /dev/null +++ b/Clion/.idea/editor.xml @@ -0,0 +1,251 @@ + + + + + \ No newline at end of file diff --git a/Clion/.idea/misc.xml b/Clion/.idea/misc.xml new file mode 100644 index 0000000..db293e8 --- /dev/null +++ b/Clion/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + + + {} + \ No newline at end of file diff --git a/Clion/.idea/modules.xml b/Clion/.idea/modules.xml new file mode 100644 index 0000000..cf65081 --- /dev/null +++ b/Clion/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Clion/.idea/vcs.xml b/Clion/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/Clion/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Clion/CMakeLists.txt b/Clion/CMakeLists.txt new file mode 100644 index 0000000..599356d --- /dev/null +++ b/Clion/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.31) +project(Clion C) + +set(CMAKE_C_STANDARD 11) + +add_executable(Clion main.c) diff --git a/Clion/main.c b/Clion/main.c new file mode 100644 index 0000000..4dd72fa --- /dev/null +++ b/Clion/main.c @@ -0,0 +1,7 @@ +#include + +int main(void) +{ + printf("Hello, World!\n"); + return 0; +} \ No newline at end of file diff --git a/Clion/test.c b/Clion/test.c new file mode 100644 index 0000000..ce0ecf2 --- /dev/null +++ b/Clion/test.c @@ -0,0 +1,10 @@ +// +// Created by ZBright on 25-5-29. +// +#include + +int main() +{ + printf("Hello World\n"); + return 0; +} \ No newline at end of file diff --git a/Clion/test.exe b/Clion/test.exe new file mode 100644 index 0000000000000000000000000000000000000000..ac41184103f1afbcf1d2e8e05539b13be62296a2 GIT binary patch literal 80466 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 literal 0 HcmV?d00001 diff --git a/Code/Project_Client.c b/Code/Project_Client.c new file mode 100644 index 0000000..e69de29 diff --git a/Code/Project_Server.c b/Code/Project_Server.c new file mode 100644 index 0000000..e69de29 diff --git a/Code/cet.c b/Code/cet.c new file mode 100644 index 0000000..c7939b6 --- /dev/null +++ b/Code/cet.c @@ -0,0 +1,54 @@ +#include +#include +#include /* See NOTES */ +#include +#include +#include +#include + +#define OWNADDR "192.168.0.17" //我自己电脑的ip地址 +#define OWNPORT 10000 //我自己电脑的该程序的端口号 + +#define SERVERADDR "192.168.0.114" //对方的服务器的IP地址 +#define SERVERPORT 20000 //对方的服务器的端口号 + +int main() +{ + //1、买手机(建立套接字) + int socketfd = socket(AF_INET, SOCK_STREAM, 0); + if(socketfd == -1) + { + printf("没钱了....,失败\n"); + return -1; + } + //2、绑定自己的电话号码(绑定自己的IP地址 和端口号) + //定义一个IPV4结构体变量,初始化自己的IP地址和端口号 + struct sockaddr_in ownAddr; + ownAddr.sin_family = AF_INET;/*地址族  IPV4*/ + ownAddr.sin_port = htons(OWNPORT);//htons 将本地端口号转为网络端口号 + ownAddr.sin_addr.s_addr = inet_addr(OWNADDR);//将本地IP地址转为网络IP地址 + + bind(socketfd, (struct sockaddr *)&ownAddr,sizeof(struct sockaddr_in)); + + //3、开始打电话(发起连接) + struct sockaddr_in serverAddr; + serverAddr.sin_family = AF_INET;/*地址族  IPV4*/ + serverAddr.sin_port = htons(SERVERPORT); //htons 将本地端口号转为网络端口号 + serverAddr.sin_addr.s_addr = inet_addr(SERVERADDR); //将本地IP地址转为网络IP地址 + + connect(socketfd,(struct sockaddr *)&serverAddr,sizeof(struct sockaddr_in)); + + //4、聊天 + while(1) + { + printf("data:"); + char buf[1024]={0}; + scanf("%s",buf); + //发送数据 + send(socketfd, buf, strlen(buf), 0); + } + //5、关闭 + close(socketfd); + + return 0; +} \ No newline at end of file diff --git a/Code/output/cet b/Code/output/cet new file mode 100644 index 0000000000000000000000000000000000000000..145341451b5c6ce5d4192fc7f966ed7ae50632d4 GIT binary patch literal 16400 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 +#include /* See NOTES */ +#include +#include +#include +#include +#include + + + +#define SERVER_ADDR "172.29.147.16" //服务器的IP地址 +#define SERVER_PORT 20000 //port 服务器的端口号 + + +int main() +{ + int ret; + //1、买手机(建立套接字) + int socketFd = socket(AF_INET, SOCK_STREAM, 0); + if(socketFd == -1){ + perror("socket error"); + exit(0); + } + //2、绑定自己的电话号码(绑定自己的IP地址和端口号) + //定义一个IPV4结构体变量,存储IP地址和端口号 + struct sockaddr_in serverAddr; + serverAddr.sin_family = AF_INET ;//IPv4 + serverAddr.sin_port = htons(SERVER_PORT);//16端口号 --本地端口号--网络端口号 + serverAddr.sin_addr.s_addr = inet_addr(SERVER_ADDR); //32IP地址 --本地IP--网络IP + + ret = bind(socketFd, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr_in)); + if(ret == -1){ + perror("bind error"); + exit(0); + } + //3、设置铃声(设置监听) + ret = listen(socketFd, 20); //20表示同时连接上来的客户端的最大数量 + if(ret == -1){ + perror("listen error"); + exit(0); + } + printf("阻塞等待新的客户端连接......\n"); + //4、坐等电话(阻塞等待客户端的连接) + int newClientFd = accept(socketFd, NULL,NULL); + if(ret == -1){ + perror("accept error"); + exit(0); + } + //注意 accept函数的返回值 表示 新的客户端的文件描述符 ,后面与客户端通信 必须使用该文件描述符 + printf("有新的客户端连接上来....\n"); + + //5、聊天 接收 数据 + while(1) + { + char buf[1024]={0}; + read(newClientFd,buf,sizeof(buf)); + printf("buf:%s\n",buf); + } + + //6、关闭 断开连接 + close(socketFd); + close(newClientFd); + + return 0; +} diff --git a/Project/client b/Project/client new file mode 100644 index 0000000000000000000000000000000000000000..3f5f29acd9cc7a483d2d2f64c09f1a0d298105c0 GIT binary patch literal 17264 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 literal 0 HcmV?d00001 diff --git a/Project/client.c b/Project/client.c new file mode 100644 index 0000000..53d748a --- /dev/null +++ b/Project/client.c @@ -0,0 +1,270 @@ +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 +#define SERVER_IP "127.0.0.1" +#define PORT 8888 + +int client_socket; +pthread_t receive_thread; +int running = 1; + +// 函数声明 +void *receive_messages(void *arg); +void handle_signal(int sig); +void login_register_menu(); + +int main() { + struct sockaddr_in server_addr; + + // 创建socket + client_socket = socket(AF_INET, SOCK_STREAM, 0); + if (client_socket == -1) { + perror("Socket creation failed"); + exit(EXIT_FAILURE); + } + + // 准备服务器地址 + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + + // 将IPv4地址从点分十进制转换为二进制形式 + if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) { + perror("Invalid address/ Address not supported"); + exit(EXIT_FAILURE); + } + + // 连接到服务器 + if (connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { + perror("Connection failed"); + exit(EXIT_FAILURE); + } + + printf("Connected to server.\n"); + + // 设置信号处理 + signal(SIGINT, handle_signal); + + // 创建接收消息的线程 + if (pthread_create(&receive_thread, NULL, receive_messages, NULL) != 0) { + perror("Thread creation failed"); + close(client_socket); + exit(EXIT_FAILURE); + } + + // 登录/注册菜单 + login_register_menu(); + + // 聊天循环 + printf("\nWelcome to the chat! Type /help for commands.\n"); + char message[BUFFER_SIZE]; + while (running) { + memset(message, 0, BUFFER_SIZE); + fgets(message, BUFFER_SIZE - 1, stdin); + + // 移除换行符 + size_t len = strlen(message); + if (len > 0 && message[len - 1] == '\n') { + message[len - 1] = '\0'; + } + + // 检查是否是退出命令 + if (strcmp(message, "/quit") == 0) { + running = 0; + break; + } + + // 发送消息到服务器 + if (send(client_socket, message, strlen(message), 0) == -1) { + perror("Send failed"); + running = 0; + } + } + + // 等待接收线程结束 + pthread_join(receive_thread, NULL); + + // 关闭socket + close(client_socket); + printf("Disconnected from server.\n"); + + return 0; +} + +void *receive_messages(void *arg) { + char buffer[BUFFER_SIZE]; + int bytes_received; + + while (running) { + memset(buffer, 0, BUFFER_SIZE); + bytes_received = recv(client_socket, buffer, BUFFER_SIZE - 1, 0); + + if (bytes_received <= 0) { + // 服务器断开连接 + printf("Server disconnected.\n"); + running = 0; + break; + } + + // 打印接收到的消息 + printf("%s", buffer); + } + + pthread_exit(NULL); +} + +void handle_signal(int sig) { + printf("\nExiting...\n"); + running = 0; + close(client_socket); + exit(EXIT_SUCCESS); +} + +void login_register_menu() { + char buffer[BUFFER_SIZE]; + int choice; + char username[BUFFER_SIZE]; + char password[BUFFER_SIZE]; + + while (running) { + // 接收菜单 + memset(buffer, 0, BUFFER_SIZE); + if (recv(client_socket, buffer, BUFFER_SIZE - 1, 0) <= 0) { + printf("Server disconnected.\n"); + running = 0; + return; + } + printf("%s", buffer); + + // 发送选择 + scanf("%d", &choice); + getchar(); // 消耗换行符 + sprintf(buffer, "%d", choice); + if (send(client_socket, buffer, strlen(buffer), 0) == -1) { + perror("Send failed"); + running = 0; + return; + } + + // 处理登录 + if (choice == 1) { + // 接收用户名提示 + memset(buffer, 0, BUFFER_SIZE); + if (recv(client_socket, buffer, BUFFER_SIZE - 1, 0) <= 0) { + printf("Server disconnected.\n"); + running = 0; + return; + } + printf("%s", buffer); + + // 发送用户名 + fgets(username, BUFFER_SIZE - 1, stdin); + username[strcspn(username, "\n")] = 0; // 移除换行符 + if (send(client_socket, username, strlen(username), 0) == -1) { + perror("Send failed"); + running = 0; + return; + } + + // 接收密码提示 + memset(buffer, 0, BUFFER_SIZE); + if (recv(client_socket, buffer, BUFFER_SIZE - 1, 0) <= 0) { + printf("Server disconnected.\n"); + running = 0; + return; + } + printf("%s", buffer); + + // 发送密码 + fgets(password, BUFFER_SIZE - 1, stdin); + password[strcspn(password, "\n")] = 0; // 移除换行符 + if (send(client_socket, password, strlen(password), 0) == -1) { + perror("Send failed"); + running = 0; + return; + } + + // 接收登录结果 + memset(buffer, 0, BUFFER_SIZE); + if (recv(client_socket, buffer, BUFFER_SIZE - 1, 0) <= 0) { + printf("Server disconnected.\n"); + running = 0; + return; + } + printf("%s", buffer); + + // 检查是否登录成功 + if (strstr(buffer, "Login successful") != NULL) { + // 接收帮助信息 + memset(buffer, 0, BUFFER_SIZE); + if (recv(client_socket, buffer, BUFFER_SIZE - 1, 0) > 0) { + printf("%s", buffer); + } + break; + } + } + // 处理注册 + else if (choice == 2) { + // 接收用户名提示 + memset(buffer, 0, BUFFER_SIZE); + if (recv(client_socket, buffer, BUFFER_SIZE - 1, 0) <= 0) { + printf("Server disconnected.\n"); + running = 0; + return; + } + printf("%s", buffer); + + // 发送用户名 + fgets(username, BUFFER_SIZE - 1, stdin); + username[strcspn(username, "\n")] = 0; // 移除换行符 + if (send(client_socket, username, strlen(username), 0) == -1) { + perror("Send failed"); + running = 0; + return; + } + + // 接收密码提示 + memset(buffer, 0, BUFFER_SIZE); + if (recv(client_socket, buffer, BUFFER_SIZE - 1, 0) <= 0) { + printf("Server disconnected.\n"); + running = 0; + return; + } + printf("%s", buffer); + + // 发送密码 + fgets(password, BUFFER_SIZE - 1, stdin); + password[strcspn(password, "\n")] = 0; // 移除换行符 + if (send(client_socket, password, strlen(password), 0) == -1) { + perror("Send failed"); + running = 0; + return; + } + + // 接收注册结果 + memset(buffer, 0, BUFFER_SIZE); + if (recv(client_socket, buffer, BUFFER_SIZE - 1, 0) <= 0) { + printf("Server disconnected.\n"); + running = 0; + return; + } + printf("%s", buffer); + } + else { + // 接收无效选择提示 + memset(buffer, 0, BUFFER_SIZE); + if (recv(client_socket, buffer, BUFFER_SIZE - 1, 0) <= 0) { + printf("Server disconnected.\n"); + running = 0; + return; + } + printf("%s", buffer); + } + } +} \ No newline at end of file diff --git a/Project/server b/Project/server new file mode 100644 index 0000000000000000000000000000000000000000..10e3d80efc50bc8b5313b5dea91a9f06f32a7afb GIT binary patch literal 26032 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 literal 0 HcmV?d00001 diff --git a/Project/server.c b/Project/server.c new file mode 100644 index 0000000..c3702f5 --- /dev/null +++ b/Project/server.c @@ -0,0 +1,471 @@ +#include +#include +#include +#include +#include +#include +#include + +#define MAX_CLIENTS 10 +#define BUFFER_SIZE 1024 +#define USERNAME_LENGTH 50 +#define PASSWORD_LENGTH 50 +#define FILENAME "./users.txt" + +typedef struct { + int socket; + char username[USERNAME_LENGTH]; + pthread_t thread; + int active; +} Client; + +Client clients[MAX_CLIENTS]; +pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; +int server_socket; + +// 函数声明 +void handle_signal(int sig); +void *handle_client(void *arg); +int find_client_index(int socket); +int find_client_index_by_username(const char *username); +void send_private_message(const char *sender, const char *recipient, const char *message); +void list_users(int client_socket); +int authenticate_user(const char *username, const char *password); +int register_user(const char *username, const char *password); +void save_user(const char *username, const char *password); + +int main() { + int client_socket; + struct sockaddr_in server_addr, client_addr; + socklen_t client_addr_len = sizeof(client_addr); + + // 创建socket + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket == -1) { + perror("Socket creation failed"); + exit(EXIT_FAILURE); + } + + // 设置socket选项 + int opt = 1; + if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) { + perror("Setsockopt failed"); + exit(EXIT_FAILURE); + } + + // 准备服务器地址 + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(8888); + + // 绑定socket + if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { + perror("Bind failed"); + exit(EXIT_FAILURE); + } + + // 监听连接 + if (listen(server_socket, 5) == -1) { + perror("Listen failed"); + exit(EXIT_FAILURE); + } + + printf("Server started. Waiting for connections...\n"); + + // 初始化客户端数组 + for (int i = 0; i < MAX_CLIENTS; i++) { + clients[i].socket = -1; + clients[i].active = 0; + } + + // 设置信号处理 + signal(SIGINT, handle_signal); + + // 接受客户端连接 + while (1) { + client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len); + if (client_socket == -1) { + perror("Accept failed"); + continue; + } + + // 查找空闲位置 + int i; + for (i = 0; i < MAX_CLIENTS; i++) { + if (clients[i].socket == -1) { + pthread_mutex_lock(&clients_mutex); + clients[i].socket = client_socket; + clients[i].active = 1; + pthread_mutex_unlock(&clients_mutex); + + // 创建线程处理客户端 + if (pthread_create(&clients[i].thread, NULL, handle_client, &clients[i]) != 0) { + perror("Thread creation failed"); + pthread_mutex_lock(&clients_mutex); + clients[i].socket = -1; + clients[i].active = 0; + pthread_mutex_unlock(&clients_mutex); + close(client_socket); + } + pthread_detach(clients[i].thread); + break; + } + } + + if (i == MAX_CLIENTS) { + // 服务器已满 + char response[] = "Server is full. Try again later.\n"; + send(client_socket, response, strlen(response), 0); + close(client_socket); + } + } + + // 关闭服务器socket + close(server_socket); + return 0; +} + +void handle_signal(int sig) { + printf("\nShutting down server...\n"); + + // 关闭所有客户端socket + pthread_mutex_lock(&clients_mutex); + for (int i = 0; i < MAX_CLIENTS; i++) { + if (clients[i].socket != -1) { + close(clients[i].socket); + clients[i].socket = -1; + clients[i].active = 0; + } + } + pthread_mutex_unlock(&clients_mutex); + + // 关闭服务器socket + close(server_socket); + exit(EXIT_SUCCESS); +} + +void *handle_client(void *arg) { + Client *client = (Client *)arg; + char buffer[BUFFER_SIZE]; + int bytes_received; + + // 登录/注册流程 + while (1) { + // 发送菜单 + char menu[] = "1. Login\n2. Register\nEnter choice: "; + send(client->socket, menu, strlen(menu), 0); + + // 接收选择 + memset(buffer, 0, BUFFER_SIZE); + bytes_received = recv(client->socket, buffer, BUFFER_SIZE - 1, 0); + if (bytes_received <= 0) { + pthread_mutex_lock(&clients_mutex); + client->active = 0; + pthread_mutex_unlock(&clients_mutex); + close(client->socket); + pthread_exit(NULL); + } + + int choice = atoi(buffer); + + // 处理登录 + if (choice == 1) { + // 请求用户名 + char username_prompt[] = "Username: "; + send(client->socket, username_prompt, strlen(username_prompt), 0); + + // 接收用户名 + memset(buffer, 0, BUFFER_SIZE); + bytes_received = recv(client->socket, buffer, BUFFER_SIZE - 1, 0); + if (bytes_received <= 0) { + pthread_mutex_lock(&clients_mutex); + client->active = 0; + pthread_mutex_unlock(&clients_mutex); + close(client->socket); + pthread_exit(NULL); + } + char username[USERNAME_LENGTH]; + strncpy(username, buffer, USERNAME_LENGTH - 1); + + // 请求密码 + char password_prompt[] = "Password: "; + send(client->socket, password_prompt, strlen(password_prompt), 0); + + // 接收密码 + memset(buffer, 0, BUFFER_SIZE); + bytes_received = recv(client->socket, buffer, BUFFER_SIZE - 1, 0); + if (bytes_received <= 0) { + pthread_mutex_lock(&clients_mutex); + client->active = 0; + pthread_mutex_unlock(&clients_mutex); + close(client->socket); + pthread_exit(NULL); + } + char password[PASSWORD_LENGTH]; + strncpy(password, buffer, PASSWORD_LENGTH - 1); + + // 验证用户 + if (authenticate_user(username, password)) { + // 检查用户名是否已被使用 + int username_in_use = 0; + pthread_mutex_lock(&clients_mutex); + for (int i = 0; i < MAX_CLIENTS; i++) { + if (i != find_client_index(client->socket) && clients[i].active && + strcmp(clients[i].username, username) == 0) { + username_in_use = 1; + break; + } + } + pthread_mutex_unlock(&clients_mutex); + + if (username_in_use) { + char response[] = "Username already in use. Please try again.\n"; + send(client->socket, response, strlen(response), 0); + } else { + // 登录成功 + strcpy(client->username, username); + char success[] = "Login successful. Welcome to the chat!\n"; + send(client->socket, success, strlen(success), 0); + + // 通知用户可用命令 + char help[] = "Available commands:\n/private - Send private message\n/list - List online users\n/quit - Exit chat\n"; + send(client->socket, help, strlen(help), 0); + + break; + } + } else { + char response[] = "Authentication failed. Please try again.\n"; + send(client->socket, response, strlen(response), 0); + } + } + // 处理注册 + else if (choice == 2) { + // 请求用户名 + char username_prompt[] = "Enter username: "; + send(client->socket, username_prompt, strlen(username_prompt), 0); + + // 接收用户名 + memset(buffer, 0, BUFFER_SIZE); + bytes_received = recv(client->socket, buffer, BUFFER_SIZE - 1, 0); + if (bytes_received <= 0) { + pthread_mutex_lock(&clients_mutex); + client->active = 0; + pthread_mutex_unlock(&clients_mutex); + close(client->socket); + pthread_exit(NULL); + } + char username[USERNAME_LENGTH]; + strncpy(username, buffer, USERNAME_LENGTH - 1); + + // 请求密码 + char password_prompt[] = "Enter password: "; + send(client->socket, password_prompt, strlen(password_prompt), 0); + + // 接收密码 + memset(buffer, 0, BUFFER_SIZE); + bytes_received = recv(client->socket, buffer, BUFFER_SIZE - 1, 0); + if (bytes_received <= 0) { + pthread_mutex_lock(&clients_mutex); + client->active = 0; + pthread_mutex_unlock(&clients_mutex); + close(client->socket); + pthread_exit(NULL); + } + char password[PASSWORD_LENGTH]; + strncpy(password, buffer, PASSWORD_LENGTH - 1); + + // 注册用户 + if (register_user(username, password)) { + char success[] = "Registration successful. You can now login.\n"; + send(client->socket, success, strlen(success), 0); + } else { + char response[] = "Registration failed. Username already exists.\n"; + send(client->socket, response, strlen(response), 0); + } + } + else { + char response[] = "Invalid choice. Please try again.\n"; + send(client->socket, response, strlen(response), 0); + } + } + + // 聊天循环 + while (1) { + memset(buffer, 0, BUFFER_SIZE); + bytes_received = recv(client->socket, buffer, BUFFER_SIZE - 1, 0); + + if (bytes_received <= 0) { + // 客户端断开连接 + break; + } + + // 检查是否是退出命令 + if (strncmp(buffer, "/quit", 5) == 0) { + break; + } + + // 检查是否是列出用户命令 + if (strncmp(buffer, "/list", 5) == 0) { + list_users(client->socket); + continue; + } + + // 检查是否是私聊命令 + if (strncmp(buffer, "/private", 7) == 0) { + char recipient[USERNAME_LENGTH]; + char message[BUFFER_SIZE - USERNAME_LENGTH - 8]; + + // 解析命令 + sscanf(buffer, "/private %s %[^\n]", recipient, message); + + // 发送私聊消息 + send_private_message(client->username, recipient, message); + continue; + } + + // 发送帮助信息 + char help[] = "Invalid command. Available commands:\n/private - Send private message\n/list - List online users\n/quit - Exit chat\n"; + send(client->socket, help, strlen(help), 0); + } + + // 客户端断开连接 + char leave_message[BUFFER_SIZE]; + snprintf(leave_message, BUFFER_SIZE, "%s has left the chat.\n", client->username); + pthread_mutex_lock(&clients_mutex); + for (int i = 0; i < MAX_CLIENTS; i++) { + if (i != find_client_index(client->socket) && clients[i].active) { + send(clients[i].socket, leave_message, strlen(leave_message), 0); + } + } + pthread_mutex_unlock(&clients_mutex); + + // 关闭客户端socket + pthread_mutex_lock(&clients_mutex); + close(client->socket); + client->socket = -1; + client->active = 0; + pthread_mutex_unlock(&clients_mutex); + + pthread_exit(NULL); +} + +int find_client_index(int socket) { + for (int i = 0; i < MAX_CLIENTS; i++) { + if (clients[i].socket == socket) { + return i; + } + } + return -1; +} + +int find_client_index_by_username(const char *username) { + pthread_mutex_lock(&clients_mutex); + for (int i = 0; i < MAX_CLIENTS; i++) { + if (clients[i].active && strcmp(clients[i].username, username) == 0) { + pthread_mutex_unlock(&clients_mutex); + return i; + } + } + pthread_mutex_unlock(&clients_mutex); + return -1; +} + +void send_private_message(const char *sender, const char *recipient, const char *message) { + int recipient_index = find_client_index_by_username(recipient); + + if (recipient_index == -1) { + char error[BUFFER_SIZE]; + snprintf(error, BUFFER_SIZE, "Error: User '%s' not found or offline.\n", recipient); + + int sender_index = find_client_index_by_username(sender); + if (sender_index != -1) { + send(clients[sender_index].socket, error, strlen(error), 0); + } + return; + } + + // 发送消息给接收者 + char private_message[BUFFER_SIZE]; + snprintf(private_message, BUFFER_SIZE, "[Private from %s]: %s\n", sender, message); + send(clients[recipient_index].socket, private_message, strlen(private_message), 0); + + // 发送确认给发送者 + char confirmation[BUFFER_SIZE]; + snprintf(confirmation, BUFFER_SIZE, "[Private to %s]: %s\n", recipient, message); + int sender_index = find_client_index_by_username(sender); + if (sender_index != -1) { + send(clients[sender_index].socket, confirmation, strlen(confirmation), 0); + } +} + +void list_users(int client_socket) { + char response[BUFFER_SIZE] = "Online users:\n"; + + pthread_mutex_lock(&clients_mutex); + for (int i = 0; i < MAX_CLIENTS; i++) { + if (clients[i].active) { + strncat(response, clients[i].username, USERNAME_LENGTH - strlen(response) - 2); + strcat(response, "\n"); + } + } + pthread_mutex_unlock(&clients_mutex); + + send(client_socket, response, strlen(response), 0); +} + +int authenticate_user(const char *username, const char *password) { + FILE *file = fopen(FILENAME, "r"); + if (file == NULL) { + return 0; + } + + char stored_username[USERNAME_LENGTH]; + char stored_password[PASSWORD_LENGTH]; + int found = 0; + + while (fscanf(file, "%s %s", stored_username, stored_password) != EOF) { + if (strcmp(username, stored_username) == 0 && strcmp(password, stored_password) == 0) { + found = 1; + break; + } + } + + fclose(file); + return found; +} + +int register_user(const char *username, const char *password) { + FILE *file = fopen(FILENAME, "r"); + if (file == NULL) { + file = fopen(FILENAME, "w"); + if (file == NULL) { + return 0; + } + fclose(file); + file = fopen(FILENAME, "r"); + } + + char stored_username[USERNAME_LENGTH]; + while (fscanf(file, "%s", stored_username) != EOF) { + if (strcmp(username, stored_username) == 0) { + fclose(file); + return 0; // 用户名已存在 + } + // 跳过密码 + fscanf(file, "%*s"); + } + fclose(file); + + // 添加新用户 + save_user(username, password); + return 1; +} + +void save_user(const char *username, const char *password) { + FILE *file = fopen(FILENAME, "a"); + if (file != NULL) { + fprintf(file, "%s %s\n", username, password); + fclose(file); + } +} \ No newline at end of file diff --git a/Project/test/Client.c b/Project/test/Client.c new file mode 100644 index 0000000..b93060c --- /dev/null +++ b/Project/test/Client.c @@ -0,0 +1,422 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_BUFFER 1024 +#define PORT 8888 +#define SERVER_IP "127.0.0.1" +#define MAX_FRIENDS 50 + +// 好友结构体 +typedef struct { + char username[50]; + int index; +} Friend; + +// 全局变量 +int client_socket; +int current_user_index = -1; +char current_username[50]; +pthread_t receive_thread; +Friend friends[MAX_FRIENDS]; +int friend_count = 0; + +// 函数声明 +void connect_to_server(); +void* receive_messages(void* arg); +void show_login_menu(); +void show_main_menu(); +void login(); +void register_user(); +void add_friend(); +void remove_friend(); +void chat_with_friend(); +void logout(); +void get_friends_list(); +void display_friends_list(); + +int main() { + connect_to_server(); + show_login_menu(); + return 0; +} + +void connect_to_server() { + struct sockaddr_in server_addr; + + // 创建socket + client_socket = socket(AF_INET, SOCK_STREAM, 0); + if (client_socket < 0) { + perror("创建Socket失败"); + exit(EXIT_FAILURE); + } + + // 设置服务器地址 + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); + + // 连接服务器 + if (connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { + perror("连接服务器失败"); + exit(EXIT_FAILURE); + } + + printf("成功连接到服务器!\n"); + // 不要在这里启动接收线程 +} + +void* receive_messages(void* arg) { + char buffer[MAX_BUFFER]; + while (1) { + memset(buffer, 0, MAX_BUFFER); + if (recv(client_socket, buffer, MAX_BUFFER, 0) <= 0) { + printf("\n连接已断开\n"); + current_user_index = -1; + close(client_socket); + connect_to_server(); + return NULL; + } + + // 处理PING消息 + if (strcmp(buffer, "PING") == 0) { + continue; + } + + // 处理好友列表消息 + if (strncmp(buffer, "FRIENDLIST", 10) == 0) { + friend_count = 0; // 重置好友计数 + char* token = strtok(buffer + 11, " "); + while (token != NULL && friend_count < MAX_FRIENDS) { + char* comma = strchr(token, ','); + if (comma != NULL) { + *comma = '\0'; + strncpy(friends[friend_count].username, token, sizeof(friends[friend_count].username)-1); + friends[friend_count].username[sizeof(friends[friend_count].username)-1] = '\0'; + friends[friend_count].index = atoi(comma + 1); + friend_count++; + } + token = strtok(NULL, " "); + } + printf("\n好友列表已更新\n"); + continue; + } + + // 处理好友操作响应 + if (strncmp(buffer, "FRIEND_ADD_SUCCESS", 17) == 0 || + strncmp(buffer, "FRIEND_REMOVE_SUCCESS", 20) == 0) { + printf("\n%s\n", buffer); + get_friends_list(); + continue; + } + + // 处理聊天消息 + if (strncmp(buffer, "CHAT", 4) == 0) { + printf("\n%s\n", buffer + 5); + } + // 处理系统消息 + else if (strncmp(buffer, "系统消息", 8) == 0 || + strncmp(buffer, "FRIEND_", 7) == 0) { + printf("\n%s\n", buffer); + } + // 处理其他消息 + else { + printf("\n%s\n", buffer); + } + + if (current_user_index != -1) { + printf("> "); + fflush(stdout); + } + } + return NULL; +} + +void show_login_menu() { + int choice; + while (1) { + printf("\n=== 登录菜单 ===\n"); + printf("1. 登录\n"); + printf("2. 注册\n"); + printf("3. 退出\n"); + printf("请选择: "); + scanf("%d", &choice); + getchar(); // 清除输入缓冲 + + switch (choice) { + case 1: + login(); + break; + case 2: + register_user(); + break; + case 3: + logout(); // 确保在退出前发送登出消息 + close(client_socket); + exit(EXIT_SUCCESS); + default: + printf("无效选择\n"); + } + } +} + +void show_main_menu() { + int choice; + while (current_user_index != -1) { // 只在用户已登录时显示菜单 + printf("\n=== 主菜单 ===\n"); + printf("1. 添加好友\n"); + printf("2. 删除好友\n"); + printf("3. 与好友聊天\n"); + printf("4. 查看好友列表\n"); + printf("5. 退出登录\n"); + printf("6. 退出程序\n"); + printf("请选择: "); + + if (scanf("%d", &choice) != 1) { + // 清除输入缓冲 + int c; + while ((c = getchar()) != '\n' && c != EOF); + printf("无效输入,请重新选择\n"); + continue; + } + getchar(); // 清除输入缓冲 + + switch (choice) { + case 1: + add_friend(); + break; + case 2: + remove_friend(); + break; + case 3: + chat_with_friend(); + break; + case 4: + get_friends_list(); + display_friends_list(); + break; + case 5: + logout(); + return; + case 6: + logout(); + close(client_socket); + exit(EXIT_SUCCESS); + default: + printf("无效选择\n"); + } + } +} + +void login() { + char username[50], password[50]; + char buffer[MAX_BUFFER]; + char response[MAX_BUFFER]; + + printf("用户名: "); + scanf("%s", username); + printf("密码: "); + scanf("%s", password); + getchar(); // 清除输入缓冲 + + snprintf(buffer, MAX_BUFFER, "LOGIN %s %s", username, password); + send(client_socket, buffer, MAX_BUFFER, 0); + + // 等待服务器响应 + memset(response, 0, MAX_BUFFER); + if (recv(client_socket, response, MAX_BUFFER, 0) <= 0) { + printf("登录失败:连接已断开\n"); + return; + } + + if (strncmp(response, "SUCCESS", 7) == 0) { + sscanf(response, "SUCCESS %d", ¤t_user_index); + strncpy(current_username, username, sizeof(current_username) - 1); + current_username[sizeof(current_username) - 1] = '\0'; + printf("登录成功!\n"); + // 登录成功后再启动接收线程 + if (pthread_create(&receive_thread, NULL, receive_messages, NULL) != 0) { + perror("创建线程失败"); + exit(EXIT_FAILURE); + } + get_friends_list(); + show_main_menu(); + } else { + printf("登录失败: %s\n", response + 5); + } +} + +void register_user() { + char username[50], password[50]; + char buffer[MAX_BUFFER]; + + printf("用户名: "); + scanf("%s", username); + printf("密码: "); + scanf("%s", password); + + snprintf(buffer, MAX_BUFFER, "REGISTER %s %s", username, password); + send(client_socket, buffer, MAX_BUFFER, 0); + + // 等待服务器响应 + memset(buffer, 0, MAX_BUFFER); + recv(client_socket, buffer, MAX_BUFFER, 0); + + if (strcmp(buffer, "SUCCESS") == 0) { + printf("注册成功!\n"); + } else { + printf("注册失败: %s\n", buffer + 5); + } +} + +void get_friends_list() { + char buffer[MAX_BUFFER]; + snprintf(buffer, MAX_BUFFER, "GETFRIENDS %d", current_user_index); + send(client_socket, buffer, MAX_BUFFER, 0); + // 等待接收线程处理好友列表 + usleep(100000); // 等待100ms +} + +void display_friends_list() { + printf("\n=== 好友列表 ===\n"); + if (friend_count == 0) { + printf("暂无好友\n"); + } else { + for (int i = 0; i < friend_count; i++) { + printf("%d. %s\n", i + 1, friends[i].username); + } + } + printf("----------------\n"); +} + +void chat_with_friend() { + char buffer[MAX_BUFFER]; + char message[MAX_BUFFER]; + int choice; + + get_friends_list(); + if (friend_count == 0) { + printf("您还没有好友,请先添加好友!\n"); + return; + } + + display_friends_list(); + printf("请选择要聊天的好友编号: "); + scanf("%d", &choice); + getchar(); // 清除输入缓冲 + + if (choice < 1 || choice > friend_count) { + printf("无效的选择!\n"); + return; + } + + int friend_index = friends[choice - 1].index; + printf("\n开始与 %s 聊天(输入'exit'退出):\n", friends[choice - 1].username); + printf("> "); + fflush(stdout); + + while (1) { + fgets(message, sizeof(message), stdin); + message[strcspn(message, "\n")] = 0; // 移除换行符 + // 限制 message 长度 + message[sizeof(message)-1] = '\0'; + if (strcmp(message, "exit") == 0) { + break; + } + int n = snprintf(buffer, MAX_BUFFER, "CHAT %d %d %s", current_user_index, friend_index, message); + if (n < 0 || n >= MAX_BUFFER) { + strcpy(&buffer[MAX_BUFFER-5], "..."); + } + send(client_socket, buffer, MAX_BUFFER, 0); + printf("> "); + fflush(stdout); + } +} + +void add_friend() { + char friend_name[50]; + char buffer[MAX_BUFFER]; + + printf("请输入要添加的好友用户名: "); + if (scanf("%49s", friend_name) != 1) { + getchar(); + printf("输入无效\n"); + return; + } + getchar(); + + snprintf(buffer, MAX_BUFFER, "ADDFRIEND %d %s", current_user_index, friend_name); + + // 设置发送超时 + struct timeval tv; + tv.tv_sec = 5; + tv.tv_usec = 0; + setsockopt(client_socket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof tv); + + if (send(client_socket, buffer, MAX_BUFFER, 0) <= 0) { + printf("发送请求失败\n"); + return; + } + + printf("添加好友请求已发送,等待服务器响应...\n"); +} + +void remove_friend() { + char buffer[MAX_BUFFER]; + + get_friends_list(); + usleep(100000); // 等待好友列表更新 + + if (friend_count == 0) { + printf("您还没有好友!\n"); + return; + } + + display_friends_list(); + printf("请输入要删除的好友编号: "); + int choice; + if (scanf("%d", &choice) != 1) { + getchar(); + printf("输入无效!\n"); + return; + } + getchar(); + + if (choice < 1 || choice > friend_count) { + printf("无效的选择!\n"); + return; + } + + // 设置发送超时 + struct timeval tv; + tv.tv_sec = 5; + tv.tv_usec = 0; + setsockopt(client_socket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof tv); + + snprintf(buffer, MAX_BUFFER, "REMOVEFRIEND %d %s", + current_user_index, + friends[choice - 1].username); + + if (send(client_socket, buffer, MAX_BUFFER, 0) <= 0) { + printf("发送请求失败\n"); + return; + } + + printf("删除好友请求已发送,等待服务器响应...\n"); +} + +void logout() { + if (current_user_index != -1) { + char buffer[MAX_BUFFER]; + snprintf(buffer, MAX_BUFFER, "LOGOUT"); + send(client_socket, buffer, MAX_BUFFER, 0); + current_user_index = -1; + printf("已退出登录\n"); + } +} \ No newline at end of file diff --git a/Project/test/Server.c b/Project/test/Server.c new file mode 100644 index 0000000..b764959 --- /dev/null +++ b/Project/test/Server.c @@ -0,0 +1,517 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_BUFFER 1024 +#define MAX_USERS 100 +#define MAX_FRIENDS 50 +#define PORT 8888 + +// 用户结构体 +typedef struct { + char username[50]; + char password[50]; + int friends[MAX_FRIENDS]; + int friend_count; + int online; + int socket; // 添加socket字段 +} User; + +// 全局变量 +User users[MAX_USERS]; +int user_count = 0; +pthread_mutex_t users_mutex = PTHREAD_MUTEX_INITIALIZER; + +// 函数声明 +void load_users(); +void save_users(); +int find_user(const char* username); +void* handle_client(void* arg); +void process_login(int client_socket, char* buffer); +void process_register(int client_socket, char* buffer); +void process_add_friend(int client_socket, char* buffer); +void process_remove_friend(int client_socket, char* buffer); +void process_chat(int client_socket, char* buffer); +void display_online_users(); // 新增函数声明 +void process_get_friends(int client_socket, char* buffer); + +int main() { + int server_socket, client_socket; + struct sockaddr_in server_addr, client_addr; + socklen_t client_len = sizeof(client_addr); + pthread_t thread_id; + + // 加载用户数据 + load_users(); + + // 创建socket + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket < 0) { + perror("创建Socket失败"); + exit(EXIT_FAILURE); + } + + // 设置服务器地址 + memset(&server_addr, 0, sizeof(server_addr)); + 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)) < 0) { + perror("绑定失败"); + exit(EXIT_FAILURE); + } + + // 监听连接 + if (listen(server_socket, 5) < 0) { + perror("监听失败"); + exit(EXIT_FAILURE); + } + + printf("服务器已启动,监听端口 %d\n", PORT); + + // 接受客户端连接 + while (1) { + client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_len); + if (client_socket < 0) { + perror("接受连接失败"); + continue; + } + + printf("新客户端连接:%s:%d\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + + // 为每个客户端创建新线程 + if (pthread_create(&thread_id, NULL, handle_client, (void*)&client_socket) != 0) { + perror("创建线程失败"); + close(client_socket); + } + } + + close(server_socket); + return 0; +} + +void load_users() { + FILE* file = fopen("Users.txt", "r"); + if (file == NULL) { + printf("未找到用户文件,将创建新文件。\n"); + return; + } + + while (fscanf(file, "%s %s %d", users[user_count].username, + users[user_count].password, &users[user_count].friend_count) == 3) { + for (int i = 0; i < users[user_count].friend_count; i++) { + fscanf(file, "%d", &users[user_count].friends[i]); + } + users[user_count].online = 0; + users[user_count].socket = -1; + user_count++; + } + + fclose(file); +} + +void save_users() { + FILE* file = fopen("Users.txt", "w"); + if (file == NULL) { + perror("无法打开用户文件"); + return; + } + + for (int i = 0; i < user_count; i++) { + fprintf(file, "%s %s %d", users[i].username, + users[i].password, users[i].friend_count); + for (int j = 0; j < users[i].friend_count; j++) { + fprintf(file, " %d", users[i].friends[j]); + } + fprintf(file, "\n"); + } + + fclose(file); +} + +int find_user(const char* username) { + for (int i = 0; i < user_count; i++) { + if (strcmp(users[i].username, username) == 0) { + return i; + } + } + return -1; +} + +void* handle_client(void* arg) { + int client_socket = *((int*)arg); + char buffer[MAX_BUFFER]; + int user_index = -1; + + // 设置socket选项,启用保活机制 + int keepalive = 1; + int keepidle = 5; // 5秒没有数据交互就开始探测 + int keepinterval = 2; // 探测间隔2秒 + int keepcount = 3; // 探测3次无响应就断开 + + setsockopt(client_socket, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)); + setsockopt(client_socket, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle)); + setsockopt(client_socket, IPPROTO_TCP, TCP_KEEPINTVL, &keepinterval, sizeof(keepinterval)); + setsockopt(client_socket, IPPROTO_TCP, TCP_KEEPCNT, &keepcount, sizeof(keepcount)); + + while (1) { + memset(buffer, 0, MAX_BUFFER); + int bytes_received = recv(client_socket, buffer, MAX_BUFFER, 0); + + // 检查连接状态 + if (bytes_received <= 0) { + pthread_mutex_lock(&users_mutex); + // 查找并更新断开连接的用户状态 + for (int i = 0; i < user_count; i++) { + if (users[i].socket == client_socket) { + user_index = i; + users[i].online = 0; + users[i].socket = -1; + printf("\n用户 %s 断开连接\n", users[i].username); + + // 通知所有在线好友 + for (int j = 0; j < users[i].friend_count; j++) { + int friend_index = users[i].friends[j]; + if (users[friend_index].online && users[friend_index].socket != -1) { + char notify[MAX_BUFFER]; + sprintf(notify, "系统消息: 您的好友 %s 已离线", users[i].username); + send(users[friend_index].socket, notify, MAX_BUFFER, 0); + } + } + break; + } + } + save_users(); + display_online_users(); + pthread_mutex_unlock(&users_mutex); + break; + } + + char command[20]; + sscanf(buffer, "%s", command); + + if (strcmp(command, "LOGIN") == 0) { + process_login(client_socket, buffer); + // 更新user_index + for (int i = 0; i < user_count; i++) { + if (users[i].socket == client_socket) { + user_index = i; + break; + } + } + } + else if (strcmp(command, "REGISTER") == 0) { + process_register(client_socket, buffer); + } + else if (strcmp(command, "ADDFRIEND") == 0) { + process_add_friend(client_socket, buffer); + } + else if (strcmp(command, "REMOVEFRIEND") == 0) { + process_remove_friend(client_socket, buffer); + } + else if (strcmp(command, "CHAT") == 0) { + process_chat(client_socket, buffer); + } + else if (strcmp(command, "LOGOUT") == 0) { + pthread_mutex_lock(&users_mutex); + // 查找当前用户 + for (int i = 0; i < user_count; i++) { + if (users[i].socket == client_socket) { + user_index = i; + break; + } + } + + if (user_index != -1) { + users[user_index].online = 0; + users[user_index].socket = -1; + // 通知所有在线好友 + for (int i = 0; i < users[user_index].friend_count; i++) { + int friend_index = users[user_index].friends[i]; + if (users[friend_index].online && users[friend_index].socket != -1) { + char notify[MAX_BUFFER]; + sprintf(notify, "系统消息: 您的好友 %s 已离线", users[user_index].username); + send(users[friend_index].socket, notify, MAX_BUFFER, 0); + } + } + save_users(); + printf("\n用户 %s 退出登录\n", users[user_index].username); + display_online_users(); + } + pthread_mutex_unlock(&users_mutex); + break; + } + else if (strcmp(command, "GETFRIENDS") == 0) { + process_get_friends(client_socket, buffer); + } + } + + // 确保在断开连接时清理用户状态 + if (user_index != -1) { + pthread_mutex_lock(&users_mutex); + users[user_index].online = 0; + users[user_index].socket = -1; + save_users(); + display_online_users(); + pthread_mutex_unlock(&users_mutex); + } + + close(client_socket); + return NULL; +} + +void process_login(int client_socket, char* buffer) { + char username[50], password[50]; + sscanf(buffer, "LOGIN %s %s", username, password); + + pthread_mutex_lock(&users_mutex); + int user_index = find_user(username); + + if (user_index == -1) { + send(client_socket, "FAIL 用户不存在", MAX_BUFFER, 0); + } + else if (strcmp(users[user_index].password, password) != 0) { + send(client_socket, "FAIL 密码错误", MAX_BUFFER, 0); + } + else { + // 如果用户已经在线,先将其标记为离线 + if (users[user_index].online) { + users[user_index].online = 0; + users[user_index].socket = -1; + } + + // 更新用户状态 + users[user_index].online = 1; + users[user_index].socket = client_socket; + save_users(); + + char response[MAX_BUFFER]; + snprintf(response, MAX_BUFFER, "SUCCESS %d", user_index); + send(client_socket, response, MAX_BUFFER, 0); + printf("\n用户 %s 登录成功\n", username); + + // 通知所有在线好友 + for (int i = 0; i < users[user_index].friend_count; i++) { + int friend_index = users[user_index].friends[i]; + if (users[friend_index].online && users[friend_index].socket != -1) { + char notify[MAX_BUFFER]; + snprintf(notify, MAX_BUFFER, "系统消息: 您的好友 %s 已上线", username); + send(users[friend_index].socket, notify, MAX_BUFFER, 0); + } + } + display_online_users(); + } + pthread_mutex_unlock(&users_mutex); +} + +void process_register(int client_socket, char* buffer) { + char username[50], password[50]; + sscanf(buffer, "REGISTER %s %s", username, password); + + pthread_mutex_lock(&users_mutex); + if (find_user(username) != -1) { + send(client_socket, "FAIL 用户名已存在", MAX_BUFFER, 0); + } + else if (user_count >= MAX_USERS) { + send(client_socket, "FAIL 用户数量已达上限", MAX_BUFFER, 0); + } + else { + strcpy(users[user_count].username, username); + strcpy(users[user_count].password, password); + users[user_count].friend_count = 0; + users[user_count].online = 0; + users[user_count].socket = -1; + user_count++; + save_users(); + send(client_socket, "SUCCESS", MAX_BUFFER, 0); + } + pthread_mutex_unlock(&users_mutex); +} + +void process_add_friend(int client_socket, char* buffer) { + int user_index; + char friend_name[50]; + sscanf(buffer, "ADDFRIEND %d %s", &user_index, friend_name); + + pthread_mutex_lock(&users_mutex); + int friend_index = find_user(friend_name); + + if (friend_index == -1) { + send(client_socket, "FAIL 好友不存在", MAX_BUFFER, 0); + } + else if (user_index == friend_index) { + send(client_socket, "FAIL 不能添加自己为好友", MAX_BUFFER, 0); + } + else { + // 检查是否已经是好友 + for (int i = 0; i < users[user_index].friend_count; i++) { + if (users[user_index].friends[i] == friend_index) { + send(client_socket, "FAIL 已经是好友关系", MAX_BUFFER, 0); + pthread_mutex_unlock(&users_mutex); + return; + } + } + + // 添加好友 + users[user_index].friends[users[user_index].friend_count++] = friend_index; + users[friend_index].friends[users[friend_index].friend_count++] = user_index; + save_users(); + send(client_socket, "SUCCESS", MAX_BUFFER, 0); + + // 通知被添加的用户 + if (users[friend_index].online && users[friend_index].socket != -1) { + char notify[MAX_BUFFER]; + snprintf(notify, MAX_BUFFER, "系统消息: %s 添加您为好友", users[user_index].username); + send(users[friend_index].socket, notify, MAX_BUFFER, 0); + } + } + pthread_mutex_unlock(&users_mutex); +} + +void process_remove_friend(int client_socket, char* buffer) { + int user_index; + char friend_name[50]; + sscanf(buffer, "REMOVEFRIEND %d %s", &user_index, friend_name); + + pthread_mutex_lock(&users_mutex); + int friend_index = find_user(friend_name); + + if (friend_index == -1) { + send(client_socket, "FAIL 好友不存在", MAX_BUFFER, 0); + pthread_mutex_unlock(&users_mutex); + return; + } + + int found = 0; + // 从用户的好友列表中移除 + for (int i = 0; i < users[user_index].friend_count; i++) { + if (users[user_index].friends[i] == friend_index) { + for (int j = i; j < users[user_index].friend_count - 1; j++) { + users[user_index].friends[j] = users[user_index].friends[j + 1]; + } + users[user_index].friend_count--; + found = 1; + break; + } + } + + if (found) { + // 从好友的好友列表中移除 + for (int i = 0; i < users[friend_index].friend_count; i++) { + if (users[friend_index].friends[i] == user_index) { + for (int j = i; j < users[friend_index].friend_count - 1; j++) { + users[friend_index].friends[j] = users[friend_index].friends[j + 1]; + } + users[friend_index].friend_count--; + break; + } + } + + save_users(); + + // 发送成功响应 + send(client_socket, "FRIEND_REMOVE_SUCCESS", MAX_BUFFER, 0); + + // 发送通知给被删除的好友 + if (users[friend_index].online && users[friend_index].socket != -1) { + char notify[MAX_BUFFER]; + snprintf(notify, MAX_BUFFER, "FRIEND_REMOVE %s 将您从好友列表中移除", + users[user_index].username); + send(users[friend_index].socket, notify, MAX_BUFFER, 0); + } + } else { + send(client_socket, "FAIL 不是好友关系", MAX_BUFFER, 0); + } + + pthread_mutex_unlock(&users_mutex); +} + +void process_chat(int client_socket, char* buffer) { + int user_index, friend_index; + char message[MAX_BUFFER]; + sscanf(buffer, "CHAT %d %d %[^\n]", &user_index, &friend_index, message); + pthread_mutex_lock(&users_mutex); + // 验证是否是好友关系 + int is_friend = 0; + for (int i = 0; i < users[user_index].friend_count; i++) { + if (users[user_index].friends[i] == friend_index) { + is_friend = 1; + break; + } + } + + if (!is_friend) { + send(client_socket, "FAIL 不是好友关系", MAX_BUFFER, 0); + } + else { + char response[MAX_BUFFER]; + // 限制 message 长度,防止溢出 + char safe_message[MAX_BUFFER/2]; + strncpy(safe_message, message, sizeof(safe_message) - 1); + safe_message[sizeof(safe_message) - 1] = '\0'; + int n = snprintf(response, MAX_BUFFER, "CHAT %s: %s", users[user_index].username, safe_message); + if (n < 0 || n >= MAX_BUFFER) { + // 被截断,补上 ... + strcpy(&response[MAX_BUFFER-5], "..."); + } + // 发送给发送者 + send(client_socket, response, MAX_BUFFER, 0); + // 发送给接收者 + if (users[friend_index].online && users[friend_index].socket != -1) { + send(users[friend_index].socket, response, MAX_BUFFER, 0); + } else { + // 好友不在线,给发送者提示 + send(client_socket, "系统消息: 对方不在线,消息未送达", MAX_BUFFER, 0); + } + } + pthread_mutex_unlock(&users_mutex); +} + +// 新增函数:显示在线用户 +void display_online_users() { + printf("\n当前在线用户:\n"); + int online_count = 0; + for (int i = 0; i < user_count; i++) { + if (users[i].online) { + printf("%d. %s\n", ++online_count, users[i].username); + } + } + if (online_count == 0) { + printf("暂无在线用户\n"); + } + printf("------------------------\n"); +} + +// 新增函数:处理获取好友列表请求 +void process_get_friends(int client_socket, char* buffer) { + int user_index; + sscanf(buffer, "GETFRIENDS %d", &user_index); + + pthread_mutex_lock(&users_mutex); + char response[MAX_BUFFER] = "FRIENDLIST "; + char temp[64]; + + for (int i = 0; i < users[user_index].friend_count; i++) { + int friend_index = users[user_index].friends[i]; + int n = snprintf(temp, sizeof(temp), "%s,%d ", users[friend_index].username, friend_index); + if (n < 0 || n >= sizeof(temp)) { + strcpy(&temp[sizeof(temp)-5], "..."); + } + if (strlen(response) + strlen(temp) < MAX_BUFFER) { + strcat(response, temp); + } else { + strcat(response, "..."); + break; + } + } + send(client_socket, response, MAX_BUFFER, 0); + pthread_mutex_unlock(&users_mutex); +} \ No newline at end of file diff --git a/Project/test/client b/Project/test/client new file mode 100644 index 0000000000000000000000000000000000000000..1aa97e68d828778f84e4a608ff6fed9239e34086 GIT binary patch literal 22048 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 a-eydyT!qnbaCi1|^MwYT;~A5QW&Z^@1lZI7 literal 0 HcmV?d00001 diff --git a/Project/test/server b/Project/test/server new file mode 100644 index 0000000000000000000000000000000000000000..8c18d30a9ba7aa32dd09b46b844b0a7707ac7d02 GIT binary patch literal 26080 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

>YiTcTRhC=+c8(Jjxv_( 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 Ry*`sKjP#FCjm?6x{{lNlncn~a literal 0 HcmV?d00001 diff --git a/Project/users.txt b/Project/users.txt new file mode 100644 index 0000000..7edc84d --- /dev/null +++ b/Project/users.txt @@ -0,0 +1 @@ +test password diff --git a/Project/新建文件夹/Client_Cursor.c b/Project/新建文件夹/Client_Cursor.c new file mode 100644 index 0000000..bcdd5a0 --- /dev/null +++ b/Project/新建文件夹/Client_Cursor.c @@ -0,0 +1,108 @@ +// client.c +#include +#include +#include +#include +#include +#include +#include "protocol.h" + +#define SERVER_IP "127.0.0.1" +#define PORT 8888 + +int sockfd; +char username[MAX_NAME_LEN]; + +// 接收消息线程 +void *recv_thread(void *arg) { + Message msg; + while (1) { + int n = recv(sockfd, &msg, sizeof(msg), 0); + if (n <= 0) break; + if (msg.type == MSG_PRIVATE_CHAT) { + printf("\n[私聊]%s: %s\n", msg.from, msg.data); + printf(">> "); + fflush(stdout); + } + } + return NULL; +} + +void menu() { + printf("1. 注册\n2. 登录\n选择: "); +} + +void chat_menu() { + printf("1. 添加好友\n2. 私聊\n3. 退出\n选择: "); +} + +int main() { + sockfd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in servaddr = {0}; + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(PORT); + inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr); + connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); + + int choice; + Message msg, reply; + while (1) { + menu(); + scanf("%d", &choice); + getchar(); + memset(&msg, 0, sizeof(msg)); + if (choice == 1) { + msg.type = MSG_REGISTER; + printf("用户名: "); fgets(msg.from, MAX_NAME_LEN, stdin); msg.from[strcspn(msg.from, "\n")] = 0; + printf("密码: "); fgets(msg.data, MAX_MSG_LEN, stdin); msg.data[strcspn(msg.data, "\n")] = 0; + send(sockfd, &msg, sizeof(msg), 0); + recv(sockfd, &reply, sizeof(reply), 0); + if (reply.type == MSG_OK) printf("注册成功\n"); + else printf("注册失败: %s\n", reply.data); + } else if (choice == 2) { + msg.type = MSG_LOGIN; + printf("用户名: "); fgets(msg.from, MAX_NAME_LEN, stdin); msg.from[strcspn(msg.from, "\n")] = 0; + printf("密码: "); fgets(msg.data, MAX_MSG_LEN, stdin); msg.data[strcspn(msg.data, "\n")] = 0; + send(sockfd, &msg, sizeof(msg), 0); + recv(sockfd, &reply, sizeof(reply), 0); + if (reply.type == MSG_OK) { + strcpy(username, msg.from); + printf("登录成功\n"); + break; + } else { + printf("登录失败: %s\n", reply.data); + } + } + } + + pthread_t tid; + pthread_create(&tid, NULL, recv_thread, NULL); + + while (1) { + chat_menu(); + scanf("%d", &choice); + getchar(); + if (choice == 1) { + msg.type = MSG_ADD_FRIEND; + strcpy(msg.from, username); + printf("好友用户名: "); fgets(msg.to, MAX_NAME_LEN, stdin); msg.to[strcspn(msg.to, "\n")] = 0; + send(sockfd, &msg, sizeof(msg), 0); + recv(sockfd, &reply, sizeof(reply), 0); + if (reply.type == MSG_OK) printf("添加好友成功\n"); + else printf("添加失败: %s\n", reply.data); + } else if (choice == 2) { + msg.type = MSG_PRIVATE_CHAT; + strcpy(msg.from, username); + printf("好友用户名: "); fgets(msg.to, MAX_NAME_LEN, stdin); msg.to[strcspn(msg.to, "\n")] = 0; + printf("消息内容: "); fgets(msg.data, MAX_MSG_LEN, stdin); msg.data[strcspn(msg.data, "\n")] = 0; + send(sockfd, &msg, sizeof(msg), 0); + recv(sockfd, &reply, sizeof(reply), 0); + if (reply.type == MSG_OK) printf("消息已发送\n"); + else printf("发送失败: %s\n", reply.data); + } else if (choice == 3) { + break; + } + } + close(sockfd); + return 0; +} \ No newline at end of file diff --git a/Project/新建文件夹/Server_Cursor.c b/Project/新建文件夹/Server_Cursor.c new file mode 100644 index 0000000..9835825 --- /dev/null +++ b/Project/新建文件夹/Server_Cursor.c @@ -0,0 +1,138 @@ +// server.c +#include +#include +#include +#include +#include +#include +#include "protocol.h" +#include "user.h" + +#define PORT 8888 +#define MAX_USERS 100 +#define MAX_CLIENTS 100 + +typedef struct { + int sockfd; + char username[MAX_NAME_LEN]; +} Client; + +User users[MAX_USERS]; +int user_count = 0; +Client clients[MAX_CLIENTS]; +int client_count = 0; +pthread_mutex_t user_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t client_mutex = PTHREAD_MUTEX_INITIALIZER; + +// 查找在线客户端 +int find_client(const char *username) { + for (int i = 0; i < client_count; i++) { + if (strcmp(clients[i].username, username) == 0) + return i; + } + return -1; +} + +// 处理客户端请求 +void *client_handler(void *arg) { + int sockfd = *(int *)arg; + char curr_user[MAX_NAME_LEN] = ""; + Message msg, reply; + while (1) { + int n = recv(sockfd, &msg, sizeof(msg), 0); + if (n <= 0) break; + memset(&reply, 0, sizeof(reply)); + switch (msg.type) { + case MSG_REGISTER: + pthread_mutex_lock(&user_mutex); + if (add_user(users, &user_count, msg.from, msg.data)) { + save_users(users, user_count); + reply.type = MSG_OK; + } else { + reply.type = MSG_FAIL; + strcpy(reply.data, "用户名已存在"); + } + pthread_mutex_unlock(&user_mutex); + send(sockfd, &reply, sizeof(reply), 0); + break; + case MSG_LOGIN: + pthread_mutex_lock(&user_mutex); + if (check_password(users, user_count, msg.from, msg.data)) { + strcpy(curr_user, msg.from); + pthread_mutex_lock(&client_mutex); + strcpy(clients[client_count].username, curr_user); + clients[client_count++].sockfd = sockfd; + pthread_mutex_unlock(&client_mutex); + reply.type = MSG_OK; + } else { + reply.type = MSG_FAIL; + strcpy(reply.data, "用户名或密码错误"); + } + pthread_mutex_unlock(&user_mutex); + send(sockfd, &reply, sizeof(reply), 0); + break; + case MSG_ADD_FRIEND: + pthread_mutex_lock(&user_mutex); + if (add_friend(users, user_count, curr_user, msg.to)) { + save_users(users, user_count); + reply.type = MSG_OK; + } else { + reply.type = MSG_FAIL; + strcpy(reply.data, "添加好友失败"); + } + pthread_mutex_unlock(&user_mutex); + send(sockfd, &reply, sizeof(reply), 0); + break; + case MSG_PRIVATE_CHAT: + pthread_mutex_lock(&client_mutex); + int idx = find_client(msg.to); + if (idx != -1) { + send(clients[idx].sockfd, &msg, sizeof(msg), 0); + reply.type = MSG_OK; + } else { + reply.type = MSG_FAIL; + strcpy(reply.data, "对方不在线"); + } + pthread_mutex_unlock(&client_mutex); + send(sockfd, &reply, sizeof(reply), 0); + break; + default: + break; + } + } + // 客户端断开,移除 + pthread_mutex_lock(&client_mutex); + for (int i = 0; i < client_count; i++) { + if (clients[i].sockfd == sockfd) { + clients[i] = clients[--client_count]; + break; + } + } + pthread_mutex_unlock(&client_mutex); + close(sockfd); + return NULL; +} + +int main() { + int listenfd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in servaddr = {0}; + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = INADDR_ANY; + servaddr.sin_port = htons(PORT); + bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); + listen(listenfd, 5); + + user_count = load_users(users, MAX_USERS); + printf("服务器启动,监听端口%d\n", PORT); + + while (1) { + struct sockaddr_in cliaddr; + socklen_t len = sizeof(cliaddr); + int connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len); + pthread_t tid; + pthread_create(&tid, NULL, client_handler, &connfd); + pthread_detach(tid); + } + close(listenfd); + return 0; +} \ No newline at end of file diff --git a/Project/新建文件夹/User.c b/Project/新建文件夹/User.c new file mode 100644 index 0000000..2fc10bf --- /dev/null +++ b/Project/新建文件夹/User.c @@ -0,0 +1,94 @@ +// user.c +#include "user.h" +#include +#include + +#define USER_FILE "users.txt" +#define MAX_LINE 256 + +// 加载所有用户 +int load_users(User users[], int max_users) { + FILE *fp = fopen(USER_FILE, "r"); + if (!fp) return 0; + int count = 0; + char line[MAX_LINE]; + while (fgets(line, sizeof(line), fp) && count < max_users) { + User *u = &users[count]; + char *p = strtok(line, " \n"); + if (!p) continue; + strcpy(u->username, p); + p = strtok(NULL, " \n"); + if (!p) continue; + strcpy(u->password, p); + u->friend_count = 0; + p = strtok(NULL, " \n"); + if (p) { + char *f = strtok(p, ","); + while (f && u->friend_count < MAX_FRIENDS) { + strcpy(u->friends[u->friend_count++], f); + f = strtok(NULL, ","); + } + } + count++; + } + fclose(fp); + return count; +} + +// 保存所有用户 +int save_users(User users[], int user_count) { + FILE *fp = fopen(USER_FILE, "w"); + if (!fp) return -1; + for (int i = 0; i < user_count; i++) { + fprintf(fp, "%s %s", users[i].username, users[i].password); + for (int j = 0; j < users[i].friend_count; j++) { + fprintf(fp, "%c%s", j == 0 ? ' ' : ',', users[i].friends[j]); + } + fprintf(fp, "\n"); + } + fclose(fp); + return 0; +} + +// 查找用户 +int find_user(User users[], int user_count, const char *username) { + for (int i = 0; i < user_count; i++) { + if (strcmp(users[i].username, username) == 0) + return i; + } + return -1; +} + +// 检查密码 +int check_password(User users[], int user_count, const char *username, const char *password) { + int idx = find_user(users, user_count, username); + if (idx == -1) return 0; + return strcmp(users[idx].password, password) == 0; +} + +// 添加用户 +int add_user(User users[], int *user_count, const char *username, const char *password) { + if (find_user(users, *user_count, username) != -1) return 0; + User *u = &users[(*user_count)++]; + strcpy(u->username, username); + strcpy(u->password, password); + u->friend_count = 0; + return 1; +} + +// 添加好友 +int add_friend(User users[], int user_count, const char *username, const char *friendname) { + int idx = find_user(users, user_count, username); + int fidx = find_user(users, user_count, friendname); + if (idx == -1 || fidx == -1) return 0; + User *u = &users[idx]; + for (int i = 0; i < u->friend_count; i++) { + if (strcmp(u->friends[i], friendname) == 0) + return 0; // 已是好友 + } + if (u->friend_count < MAX_FRIENDS) { + strcpy(u->friends[u->friend_count++], friendname); + return 1; + } + return 0; +} \ No newline at end of file diff --git a/Project/新建文件夹/User.h b/Project/新建文件夹/User.h new file mode 100644 index 0000000..42e8aa1 --- /dev/null +++ b/Project/新建文件夹/User.h @@ -0,0 +1,21 @@ +// user.h +#ifndef USER_H +#define USER_H + +#define MAX_FRIENDS 10 + +typedef struct { + char username[32]; + char password[32]; + char friends[MAX_FRIENDS][32]; + int friend_count; +} User; + +int load_users(User users[], int max_users); +int save_users(User users[], int user_count); +int find_user(User users[], int user_count, const char *username); +int check_password(User users[], int user_count, const char *username, const char *password); +int add_user(User users[], int *user_count, const char *username, const char *password); +int add_friend(User users[], int user_count, const char *username, const char *friendname); + +#endif \ No newline at end of file diff --git a/Project/新建文件夹/protocol.h b/Project/新建文件夹/protocol.h new file mode 100644 index 0000000..ef0ce70 --- /dev/null +++ b/Project/新建文件夹/protocol.h @@ -0,0 +1,22 @@ +// protocol.h +#ifndef PROTOCOL_H +#define PROTOCOL_H + +#define MSG_REGISTER 1 +#define MSG_LOGIN 2 +#define MSG_ADD_FRIEND 3 +#define MSG_PRIVATE_CHAT 4 +#define MSG_OK 100 +#define MSG_FAIL 101 + +#define MAX_NAME_LEN 32 +#define MAX_MSG_LEN 256 + +typedef struct { + int type; // 消息类型 + char from[MAX_NAME_LEN]; + char to[MAX_NAME_LEN]; + char data[MAX_MSG_LEN]; +} Message; + +#endif \ No newline at end of file diff --git a/Project/新建文件夹/users.txt b/Project/新建文件夹/users.txt new file mode 100644 index 0000000..7edc84d --- /dev/null +++ b/Project/新建文件夹/users.txt @@ -0,0 +1 @@ +test password