13#define DEFAULT_TCP_PORT 5100
15#define BUFFER_SIZE 1024
64 pthread_mutex_t *client_mutex;
153 printf(
"현재 접속 중인 유저 목록:\n");
157 printf(
"User: %s, Room: %d\n", client_info->
username, client_info->
room_id);
161 for (
int room_id = 1; room_id <= 5; room_id++) {
166 if (client_info->
room_id == room_id) {
171 printf(
"Room %d: %d명\n", room_id, user_count);
184 if (client_info->
room_id == room_id) {
185 send(client_info->
client_fd,
"The room has been closed. You have been kicked out.\n", strlen(
"The room has been closed. You have been kicked out.\n"), 0);
190 printf(
"Room %d has been closed, and all users have been kicked.\n", room_id);
210 strcpy(client_info->
username, username);
211 pthread_mutex_t *client_mutex = (pthread_mutex_t *)malloc(
sizeof(pthread_mutex_t));
212 pthread_mutex_init(client_mutex, NULL);
229 printf(
"클라이언트 %d 연결 종료 및 메모리 해제 완료\n", client_info->
client_id);
243 if (strcmp(client_info->
username, username) == 0) {
244 send(client_info->
client_fd,
"You have been kicked from the chat.\n", strlen(
"You have been kicked from the chat.\n"), 0);
246 printf(
"User %s has been kicked.\n", username);
270 if (client_info->
room_id == room_id && client_info->
client_fd != sender_fd) {
290 time_t now = time(NULL);
291 struct tm *t = localtime(&now);
298 strftime(log_path,
sizeof(log_path),
"/var/log/chatlog_%Y%m%d.log", t);
303 FILE *log_file = fopen(log_path,
"a");
304 if (log_file == NULL) {
305 perror(
"로그 파일을 열 수 없습니다.");
311 fprintf(log_file,
"%s\n", message);
330 memset(buffer, 0,
sizeof(buffer));
333 printf(
"사용자명 수신 실패 또는 클라이언트 연결 종료\n");
339 printf(
"사용자명: %s\n", client_info->
username);
342 memset(buffer, 0,
sizeof(buffer));
345 printf(
"채팅방 수신 실패 또는 클라이언트 연결 종료\n");
349 printf(
"클라이언트 %d 연결 종료에 따른 뮤텍스 파괴", client_info->
client_id);
350 pthread_mutex_destroy(client_info -> client_mutex);
351 free(client_info -> client_mutex);
352 printf(
"뮤텍스 파괴 완료. 클라이언트 아이디 : [ %d ] -> destroyed\n", client_info->
client_id);
354 if(client_info->
room_id != 0) {
355 printf(
"클라이언트 %d가 채팅방 %d에서 퇴장했습니다.\n", client_info->
client_id, client_info->
room_id);
357 printf(
"클라이언트 %d 연결 종료\n", client_info->
client_id);
364 client_info->
room_id = atoi(buffer);
365 printf(
"클라이언트 %d가 채팅방 %d에 입장했습니다.\n", client_info->
client_id, client_info->
room_id);
369 buffer[nbytes] =
'\0';
370 printf(
"클라이언트 %d (%s) 메시지: %s\n", client_info->
client_id, client_info->
username, buffer);
374 printf(
"클라이언트 %d 연결 종료\n", client_info->
client_id);
377 printf(
"클라이언트 %d 연결 종료. 뮤텍스 파괴 중...\n", client_info->
client_id);
378 pthread_mutex_destroy(client_info -> client_mutex);
379 free(client_info -> client_mutex);
380 printf(
"뮤텍스 파괴 완료. 클라이언트 아이디 : [ %d ] -> destroyed\n", client_info->
client_id);
394 va_start(args, num_tcp_proc);
396 for (
int i = 0; i < num_tcp_proc; i++) {
397 int ssock, client_count = 1;
399 struct sockaddr_in servaddr, cliaddr;
402 char client_ip[INET_ADDRSTRLEN];
404 int port = va_arg(args,
int);
406 if ((ssock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
412 if (setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &enable,
sizeof(
int)) < 0) {
413 perror(
"setsockopt(SO_REUSEADDR) failed");
417 memset(&servaddr, 0,
sizeof(servaddr));
418 servaddr.sin_family = AF_INET;
419 servaddr.sin_addr.s_addr = htons(INADDR_ANY);
420 servaddr.sin_port = htons(port);
422 if (bind(ssock, (
struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0) {
427 if (listen(ssock, 8) < 0) {
431 printf(
"서버가 포트 %d에서 듣고 있습니다.\n", port);
434 printf(
"서버가 클라이언트의 연결을 기다립니다...\n");
440 clen =
sizeof(cliaddr);
441 int csock = accept(ssock, (
struct sockaddr *)&cliaddr, &clen);
443 inet_ntop(AF_INET, &cliaddr.sin_addr, client_ip, INET_ADDRSTRLEN);
444 printf(
"[ 클라이언트 %d가 연결되었습니다. IP: %s ]\n", client_count, client_ip);
446 pthread_mutex_t *client_mutex = (pthread_mutex_t *)malloc(
sizeof(pthread_mutex_t));
447 pthread_mutex_init(client_mutex, NULL);
461 printf(
"mutex %d called\n", client_info->
client_id);
489 buffer[strcspn(buffer,
"\n")] =
'\0';
492 if (strcmp(buffer,
"exit") == 0 || strcmp(buffer,
"...") == 0) {
493 printf(
"채팅을 종료합니다.\n");
498 if (strcmp(buffer,
"list") == 0) {
503 if (strncmp(buffer,
"kill ", 5) == 0) {
504 char *username = buffer + 5;
509 if (strncmp(buffer,
"kill room ", 10) == 0) {
510 int room_id = atoi(buffer + 10);
515 if (strncmp(buffer,
"grep -r", 7) == 0) {
517 char log_filename[50];
518 time_t now = time(NULL);
519 struct tm *t = localtime(&now);
522 strftime(log_filename,
sizeof(log_filename),
"/var/log/chatlog_%Y%m%d.log", t);
525 snprintf(command,
sizeof(command),
"%s %s", buffer, log_filename);
529 if (strlen(buffer) > 0) {
543 snprintf(server_message,
sizeof(server_message),
"[서버]: %s", message);
549 write(i, server_message, strlen(server_message));
574 int fd = open(
"/home/pi/Desktop/veda/workspace/save/chat_server.log", O_RDWR | O_CREAT | O_APPEND, 0600);
577 printf(
"로그 파일 열기 실패\n");
578 printf(
"server.c 내의 daemonize()함수에서 로그 파일을 열지 못했습니다. 새로 시작하는 장소이니 올바른 경로를 지정하세요.\n");
581 printf(
"로그 파일 열기 성공\n");
582 printf(
"올바른 경로로 지정이 되었고, 시작이 되었습니다. 이 작동은 client에서 한번 Exit를 하면 server도 종료가 되므로, 반드시 daemon_start.sh를 사용하여 실행을 하세요.\n");
586 dup2(fd, STDOUT_FILENO);
587 dup2(fd, STDERR_FILENO);
596 if ((chdir(
"/")) < 0) {
602 close(STDOUT_FILENO);
603 close(STDERR_FILENO);
607 printf(
"\033[0;34m ▌ \033[0;33m▐·▄▄▄ .·▄▄▄▄ ▄▄▄· ▄▄▄· ▄▄· ▄▄▄· ·▄▄▄▄ ▄▄▄ .• \033[0;34m▌ \033[0;37m▄ ·. ▄· ▄▌\n");
608 printf(
"\033[0;34m▪█·█▌▀▄.▀·██▪ ██ ▐█ ▀█ ▐█ ▀█ ▐█ ▌▪▐█ ▀█ ██▪ ██ ▀▄.▀··\033[0;37m██ ▐███▪▐█▪██▌\n");
609 printf(
"\033[0;34m▐█▐█•▐▀▀▪▄▐█· ▐█▌▄█▀▀█ ▄█▀▀█ ██ ▄▄▄█▀▀█ ▐█· ▐█▌▐▀▀▪▄▐█ \033[0;37m▌▐▌▐█·▐█▌▐█▪\n");
610 printf(
"\033[0;34m ███ ▐█▄▄▌██. ██ ▐█ ▪▐▌ ▐█ ▪▐▌▐███▌▐█ ▪▐▌██. ██ ▐█▄▄▌\033[0;37m██ ██▌▐█▌ ▐█▀·.\n");
611 printf(
"\033[0;34m. \033[0;33m▀ ▀▀▀ ▀▀▀▀▀• ▀ ▀ ▀ ▀ ·▀▀▀ ▀ ▀ ▀▀▀▀▀• \033[0;37m▀▀▀ ▀▀ █▪▀▀▀ ▀ •\n");
623 printf(
"자동으로 데몬화하여 서버를 시작합니다.\n");
635 printf(
"\nPress Enter to continue...");
636 while (getchar() !=
'\n');
637 printf(
"이 프로그램을 자동으로 데몬 화 하시겠습니까? (y/n): ");
641 if (yn ==
'y' || yn ==
'n') {
644 printf(
"잘못된 입력입니다. (y/n): ");
645 while (getchar() !=
'\n');
651 printf(
"데몬화를 하지 않습니다.\n");
698#define MAX_CLIENTS 10
699#define BUFFER_SIZE 1024
709 struct sockaddr_in server_addr;
713 va_start(args, num_args);
715 const char *server_ip = va_arg(args,
const char *);
716 int port = va_arg(args,
int);
721 network_fd = socket(AF_INET, SOCK_STREAM, 0);
722 if (network_fd < 0) {
723 perror(
"socket() 생성 실패");
731 memset(&server_addr, 0,
sizeof(server_addr));
732 server_addr.sin_family = AF_INET;
733 server_addr.sin_addr.s_addr = inet_addr(server_ip);
734 server_addr.sin_port = htons(port);
737 if (bind(network_fd, (
struct sockaddr *)&server_addr,
sizeof(server_addr)) < 0) {
745 perror(
"listen() 실패");
753 kernel_printf(
"**************************************************\n");
754 if (system(
"lsof -i :5100") != 0) {
755 perror(
"lsof 명령 실행 실패");
760 kernel_printf(
"**************************************************\n");
void manual_server_mode()
수동 서버 관리 모드 함수
#define MAX_CLIENTS
main 함수
void send_server_message(char *message)
서버 메시지를 브로드캐스트하는 함수
void * server_input_handler(void *arg)
서버 측에서 사용자 입력을 처리하는 스레드 함수
void broadcast_message(int sender_fd, char *message, int room_id)
특정 채팅방에 있는 모든 클라이언트에게 메시지를 브로드캐스트하는 함수
pthread_mutex_t log_mutex
void kill_user(const char *username)
클라이언트를 강제로 퇴장시키는 함수
void log_chat_message(const char *message)
서버 측에서 발생한 채팅 메시지를 로그로 저장하는 함수
SmartPtr client_infos[MAX_CLIENTS]
클라이언트 정보를 스마트 포인터로 관리하는 배열
void daemonize()
daemonize 함수 구현
int create_network_tcp_process(int num_tcp_proc,...)
TCP 서버를 생성하고 클라이언트 연결을 처리하는 함수
void kill_room(int room_id)
클라이언트를 강제로 퇴장시키는 함수
void release_client(int sock)
클라이언트 정보를 스마트 포인터로 관리하는 배열
UniquePtr create_unique_ptr(size_t size, void(*deleter)(void *))
클라이언트 정보를 스마트 포인터로 관리하는 배열
void kernel_chat(int num_args,...)
네트워크와 클라이언트 간의 채팅 처리 함수
void auto_daemon_mode()
자동 데몬화 모드 함수
void add_new_client(int sock, int client_id, const char *username)
클라이언트 정보를 스마트 포인터로 관리하는 배열
void * client_handler(void *arg)
클라이언트와의 통신을 처리하는 스레드 함수
void list_users()
네트워크와 클라이언트 간의 채팅 처리 함수
SmartPtr create_smart_ptr(size_t size,...)
스마트 포인터를 생성하는 함수 (가변 인자 사용)
void release_shared_ptr(SharedPtr *sp)
shared_ptr 참조 카운트 감소 및 메모리 해제
kernel_printf("5-4 = %d\n", 1)
char username[BUFFER_SIZE]
pthread_mutex_t * client_mutex