138 lines
4.2 KiB
C
138 lines
4.2 KiB
C
// server.c
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <netinet/in.h>
|
|
#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;
|
|
} |