#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); }