Linux/Project/test/Client.c

422 lines
11 KiB
C
Raw 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>
#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", &current_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");
}
}