Linux/Project/test/Server.c
2025-06-10 23:43:56 +08:00

517 lines
17 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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