Linux/Project/test/Server.c

517 lines
17 KiB
C
Raw Permalink Normal View History

2025-06-10 23:43:56 +08:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <netinet/tcp.h>
#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);
}