My Project
Loading...
Searching...
No Matches
kernel_chat.c
Go to the documentation of this file.
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <sys/socket.h>
6#include <arpa/inet.h>
7#include <stdarg.h>
8#include "kernel_smartptr.h"
9#include "kernel_uniqueptr.h"
10#include <fcntl.h>
11#include <pthread.h>
12
13#define DEFAULT_TCP_PORT 5100
14#define MAX_CLIENTS 10
15#define BUFFER_SIZE 1024
16
17
23void auto_daemon_mode();
25
26
38void list_users();
39
45void kill_user(const char *username);
46
52void kill_room(int room_id);
53
59typedef struct {
60 int client_fd;
61 int client_id;
62 int room_id;
63 char username[BUFFER_SIZE];
64 pthread_mutex_t *client_mutex;
66
73
79UniquePtr create_unique_ptr(size_t size, void (*deleter)(void*));
80
88int create_network_tcp_process(int num_tcp_proc, ...);
89
97void broadcast_message(int sender_fd, char *message, int room_id);
98
104void log_chat_message(const char *message);
105
112void *client_handler(void *arg);
113
120void release_client(int sock);
121
129void *server_input_handler(void *arg);
130
137void send_server_message(char *message);
138
145void kill_user(const char *username);
146
153 printf("현재 접속 중인 유저 목록:\n");
154 for (int i = 0; i < MAX_CLIENTS; i++) {
155 if (client_infos[i].ptr != NULL) {
156 ClientInfo *client_info = (ClientInfo *)client_infos[i].ptr;
157 printf("User: %s, Room: %d\n", client_info->username, client_info->room_id);
158 }
159 }
160
161 for (int room_id = 1; room_id <= 5; room_id++) {
162 int user_count = 0;
163 for (int i = 0; i < MAX_CLIENTS; i++) {
164 if (client_infos[i].ptr != NULL) {
165 ClientInfo *client_info = (ClientInfo *)client_infos[i].ptr;
166 if (client_info->room_id == room_id) {
167 user_count++;
168 }
169 }
170 }
171 printf("Room %d: %d명\n", room_id, user_count);
172 }
173}
174
180void kill_room(int room_id) {
181 for (int i = 0; i < MAX_CLIENTS; i++) {
182 if (client_infos[i].ptr != NULL) {
183 ClientInfo *client_info = (ClientInfo *)client_infos[i].ptr;
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);
186 release_client(i); // Properly release client
187 }
188 }
189 }
190 printf("Room %d has been closed, and all users have been kicked.\n", room_id);
191}
192
200
206void add_new_client(int sock, int client_id, const char *username) {
207 ClientInfo *client_info = (ClientInfo *)malloc(sizeof(ClientInfo));
208 client_info->client_fd = sock;
209 client_info->client_id = client_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);
213 client_info->client_mutex = client_mutex;
214
215 // client_infos[sock] = create_smart_ptr(client_info, free);
216 client_infos[sock] = create_smart_ptr(sizeof(ClientInfo), client_info, free);
217}
218
224void release_client(int sock) {
225 if (client_infos[sock].ptr != NULL) {
226 ClientInfo *client_info = (ClientInfo *)client_infos[sock].ptr;
227 close(client_info->client_fd);
229 printf("클라이언트 %d 연결 종료 및 메모리 해제 완료\n", client_info->client_id);
230 }
231}
232
233
239void kill_user(const char *username) {
240 for (int i = 0; i < MAX_CLIENTS; i++) {
241 if (client_infos[i].ptr != NULL) {
242 ClientInfo *client_info = (ClientInfo *)client_infos[i].ptr;
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);
245 release_client(i); // Properly release client
246 printf("User %s has been kicked.\n", username);
247 break;
248 }
249 }
250 }
251}
252
260void broadcast_message(int sender_fd, char *message, int room_id) {
262 ClientInfo *sender_info = (ClientInfo *)client_infos[sender_fd].ptr;
263
264 snprintf(broadcast_message, sizeof(broadcast_message), "[%s]: %s", sender_info->username, message);
266
267 for (int i = 0; i < MAX_CLIENTS; i++) {
268 if (client_infos[i].ptr != NULL) {
269 ClientInfo *client_info = (ClientInfo *)client_infos[i].ptr;
270 if (client_info->room_id == room_id && client_info->client_fd != sender_fd) {
271 write(client_info->client_fd, broadcast_message, strlen(broadcast_message));
272 }
273 }
274 }
275}
276
277
278#include <time.h>
279
280pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
281
287void log_chat_message(const char *message) {
288 // 절대 경로로 로그 파일 지정
289 char log_path[BUFFER_SIZE];
290 time_t now = time(NULL);
291 struct tm *t = localtime(&now);
292
293 // 현재 날짜를 기반으로 로그 파일명을 만듦
294 // 반드시 touch 명령어로 해당 파일을 미리 생성해두어야 함
295 // 권한에 대해서도 고려해야 함
296 // sudo touch /var/log/chatlog_20240915.log
297 // sudo chmod 777 /var/log/chatlog_20240915.log
298 strftime(log_path, sizeof(log_path), "/var/log/chatlog_%Y%m%d.log", t);
299
300 // 뮤텍스 잠금으로 동시 접근 제어
301 pthread_mutex_lock(&log_mutex);
302
303 FILE *log_file = fopen(log_path, "a");
304 if (log_file == NULL) {
305 perror("로그 파일을 열 수 없습니다.");
306 pthread_mutex_unlock(&log_mutex); // 잠금 해제
307 return;
308 }
309
310 // 로그 파일에 메시지 기록
311 fprintf(log_file, "%s\n", message);
312 fclose(log_file);
313
314 // 뮤텍스 잠금 해제
315 pthread_mutex_unlock(&log_mutex);
316}
317
323void *client_handler(void *arg) {
324 SmartPtr *sp = (SmartPtr *)arg;
325 ClientInfo *client_info = (ClientInfo *)sp->ptr;
326 char buffer[BUFFER_SIZE];
327 int nbytes;
328
329 // 사용자명 수신
330 memset(buffer, 0, sizeof(buffer));
331 nbytes = read(client_info->client_fd, buffer, BUFFER_SIZE);
332 if (nbytes <= 0) {
333 printf("사용자명 수신 실패 또는 클라이언트 연결 종료\n");
334 close(client_info->client_fd);
335 release(sp);
336 return NULL;
337 }
338 strncpy(client_info->username, buffer, BUFFER_SIZE);
339 printf("사용자명: %s\n", client_info->username);
340
341 // 채팅방 선택 수신
342 memset(buffer, 0, sizeof(buffer));
343 nbytes = read(client_info->client_fd, buffer, BUFFER_SIZE);
344 if (nbytes <= 0) {
345 printf("채팅방 수신 실패 또는 클라이언트 연결 종료\n");
346 close(client_info->client_fd);
347
348 // 클라이언트 종료 시 뮤텍스 제거
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);
353
354 if(client_info->room_id != 0) {
355 printf("클라이언트 %d가 채팅방 %d에서 퇴장했습니다.\n", client_info->client_id, client_info->room_id);
356 } else {
357 printf("클라이언트 %d 연결 종료\n", client_info->client_id);
358 }
359
360 release(sp);
361 return NULL;
362 }
363
364 client_info->room_id = atoi(buffer);
365 printf("클라이언트 %d가 채팅방 %d에 입장했습니다.\n", client_info->client_id, client_info->room_id);
366
367 // 메시지 처리
368 while ((nbytes = read(client_info->client_fd, buffer, BUFFER_SIZE)) > 0) {
369 buffer[nbytes] = '\0';
370 printf("클라이언트 %d (%s) 메시지: %s\n", client_info->client_id, client_info->username, buffer);
371 broadcast_message(client_info->client_fd, buffer, client_info->room_id);
372 }
373
374 printf("클라이언트 %d 연결 종료\n", client_info->client_id);
375
376 // 뮤텍스 파괴 및 참조 감소 확인
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);
381
382 close(client_info->client_fd);
383 release(sp); // 스마트 포인터 해제
384 return NULL;
385}
392int create_network_tcp_process(int num_tcp_proc, ...) {
393 va_list args;
394 va_start(args, num_tcp_proc);
395
396 for (int i = 0; i < num_tcp_proc; i++) {
397 int ssock, client_count = 1;
398 socklen_t clen;
399 struct sockaddr_in servaddr, cliaddr;
400 // char buffer[BUFFER_SIZE];
401 // const char *ip_address = va_arg(args, const char*);
402 char client_ip[INET_ADDRSTRLEN];
403
404 int port = va_arg(args, int);
405
406 if ((ssock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
407 perror("socket()");
408 return -1;
409 }
410
411 int enable = 1;
412 if (setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
413 perror("setsockopt(SO_REUSEADDR) failed");
414 return -1;
415 }
416
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);
421
422 if (bind(ssock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
423 perror("bind()");
424 return -1;
425 }
426
427 if (listen(ssock, 8) < 0) {
428 perror("listen()");
429 return -1;
430 } else {
431 printf("서버가 포트 %d에서 듣고 있습니다.\n", port);
432 }
433
434 printf("서버가 클라이언트의 연결을 기다립니다...\n");
435
436 pthread_t tid;
437 pthread_create(&tid, NULL, server_input_handler, NULL); // 서버 입력 처리 스레드 생성
438
439 while (1) {
440 clen = sizeof(cliaddr);
441 int csock = accept(ssock, (struct sockaddr *)&cliaddr, &clen);
442 if (csock > 0) {
443 inet_ntop(AF_INET, &cliaddr.sin_addr, client_ip, INET_ADDRSTRLEN);
444 printf("[ 클라이언트 %d가 연결되었습니다. IP: %s ]\n", client_count, client_ip);
445
446 pthread_mutex_t *client_mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
447 pthread_mutex_init(client_mutex, NULL);
448
449 ClientInfo *client_info = (ClientInfo *)malloc(sizeof(ClientInfo));
450 client_info->client_fd = csock;
451 client_info->client_id = client_count++;
452 client_info->client_mutex = client_mutex;
453
454 // 클라이언트 정보를 스마트 포인터로 관리
455 // client_infos[csock] = create_smart_ptr(client_info, free);
456 client_infos[csock] = create_smart_ptr(sizeof(ClientInfo), client_info, free);
457
458 // 클라이언트 스레드 생성
459 pthread_create(&tid, NULL, client_handler, (void *)&client_infos[csock]);
460
461 printf("mutex %d called\n", client_info->client_id);
462
463 // 추가: 클라이언트 종료 시 뮤텍스 제거
464 pthread_detach(tid); // 스레드 분리
465 }
466 }
467
468 close(ssock); // 소켓 닫기
469 }
470
471 va_end(args);
472 return 0;
473}
474
482void *server_input_handler(void *arg) {
483 (void)arg; // 미사용 인자 처리
484 char buffer[BUFFER_SIZE];
485
486 while (1) {
487 // 표준 입력으로부터 메시지 입력받기
488 fgets(buffer, BUFFER_SIZE, stdin);
489 buffer[strcspn(buffer, "\n")] = '\0'; // 개행 문자 제거
490
491 // 종료 명령어 처리
492 if (strcmp(buffer, "exit") == 0 || strcmp(buffer, "...") == 0) {
493 printf("채팅을 종료합니다.\n");
494 exit(0);
495 }
496
497 // list 명령어 처리
498 if (strcmp(buffer, "list") == 0) {
499 list_users();
500 }
501
502 // kill 명령어 처리
503 if (strncmp(buffer, "kill ", 5) == 0) {
504 char *username = buffer + 5;
505 kill_user(username);
506 }
507
508 // kill room 명령어 처리
509 if (strncmp(buffer, "kill room ", 10) == 0) {
510 int room_id = atoi(buffer + 10);
511 kill_room(room_id);
512 }
513
514 // grep -r 명령어 처리
515 if (strncmp(buffer, "grep -r", 7) == 0) {
516 char command[BUFFER_SIZE + 100];
517 char log_filename[50];
518 time_t now = time(NULL);
519 struct tm *t = localtime(&now);
520
521 // 로그 파일명에 날짜 붙이기
522 strftime(log_filename, sizeof(log_filename), "/var/log/chatlog_%Y%m%d.log", t);
523
524 // grep 명령어에 로그 파일 경로 포함
525 snprintf(command, sizeof(command), "%s %s", buffer, log_filename);
526 system(command); // 로그 파일에서 grep 명령 실행
527 }
528
529 if (strlen(buffer) > 0) {
530 send_server_message(buffer); // 서버 메시지 전송
531 }
532 }
533 return NULL;
534}
541void send_server_message(char *message) {
542 char server_message[BUFFER_SIZE + 50];
543 snprintf(server_message, sizeof(server_message), "[서버]: %s", message);
544 log_chat_message(server_message);
545
546 // 채팅방에 있는 클라이언트들에게 메시지 전송
547 for (int i = 0; i < MAX_CLIENTS; i++) {
548 if (client_infos[i].ptr != NULL) {
549 write(i, server_message, strlen(server_message));
550 }
551 }
552}
553
559void daemonize() {
560 pid_t pid, sid;
561
562 pid = fork();
563 if (pid < 0) {
564 exit(EXIT_FAILURE);
565 }
566
567 if (pid > 0) {
568 exit(EXIT_SUCCESS); // 부모 프로세스 종료
569 }
570
571 // umask(0);
572
573 // 로그 파일을 엽니다. 기존 코드에서 파일을 올바르게 여는지 확인하세요.
574 int fd = open("/home/pi/Desktop/veda/workspace/save/chat_server.log", O_RDWR | O_CREAT | O_APPEND, 0600);
575 if (fd == -1) {
576 perror("open log");
577 printf("로그 파일 열기 실패\n");
578 printf("server.c 내의 daemonize()함수에서 로그 파일을 열지 못했습니다. 새로 시작하는 장소이니 올바른 경로를 지정하세요.\n");
579 exit(EXIT_FAILURE);
580 } else {
581 printf("로그 파일 열기 성공\n");
582 printf("올바른 경로로 지정이 되었고, 시작이 되었습니다. 이 작동은 client에서 한번 Exit를 하면 server도 종료가 되므로, 반드시 daemon_start.sh를 사용하여 실행을 하세요.\n");
583 }
584
585 // 로그 파일로 stdout과 stderr 리다이렉션
586 dup2(fd, STDOUT_FILENO);
587 dup2(fd, STDERR_FILENO);
588 close(fd); // 파일 디스크립터 닫기
589
590 // 세션 ID 설정
591 sid = setsid();
592 if (sid < 0) {
593 exit(EXIT_FAILURE);
594 }
595
596 if ((chdir("/")) < 0) {
597 exit(EXIT_FAILURE);
598 }
599
600 // stdin, stdout, stderr 닫기
601 close(STDIN_FILENO);
602 close(STDOUT_FILENO);
603 close(STDERR_FILENO);
604}
605
606void logo() {
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");
612
613 // 색상 리셋
614 printf("\033[0m");
615}
616
623 printf("자동으로 데몬화하여 서버를 시작합니다.\n");
624 daemonize(); // 데몬화 함수 호출
626}
627
634 char yn = '\0';
635 printf("\nPress Enter to continue...");
636 while (getchar() != '\n'); // Enter 키가 눌릴 때까지 대기
637 printf("이 프로그램을 자동으로 데몬 화 하시겠습니까? (y/n): ");
638
639 while (1) {
640 yn = getchar(); // 한 문자를 입력받음
641 if (yn == 'y' || yn == 'n') {
642 break; // y 또는 n을 입력받으면 루프 종료
643 }
644 printf("잘못된 입력입니다. (y/n): ");
645 while (getchar() != '\n'); // 버퍼를 비워서 남은 입력을 처리
646 }
647
648 if (yn == 'y') {
649 daemonize(); // 데몬화 함수 호출
650 } else {
651 printf("데몬화를 하지 않습니다.\n");
652 }
653
655}
656
657// /**
658// * @brief main 함수
659// * @param void
660// * @return int
661// */
662// int main()
663// {
664// char yn = '\0'; // 문자를 저장할 변수
665
666// // 스크립트를 통해 바로 시작을 하고 싶으면
667// auto_daemon_mode();
668
669// // server코드를 통해 직접 관리하고 싶으면
670// /*
671// // 로고 출력
672// logo();
673 // printf("이 프로그램을 자동으로 데몬 화 하고 싶으시다면 스크립트를 참조하세요.\n");
674
675 // // 사용자가 동작 방식을 선택할 수 있게 함
676 // printf("서버 동작 방식을 선택하세요: \n");
677 // printf("1. 자동 데몬화\n");
678 // printf("2. 수동 서버 관리\n");
679 // printf("선택: ");
680
681 // yn = getchar();
682 // while (getchar() != '\n'); // 남은 입력 버퍼 비우기
683
684 // if (yn == '1') {
685 // auto_daemon_mode(); // 자동 데몬화 모드 실행
686 // } else if (yn == '2') {
687 // manual_server_mode(); // 수동 서버 관리 모드 실행
688 // } else {
689 // printf("잘못된 선택입니다. 프로그램을 종료합니다.\n");
690 // return -1;
691 // }
692// */
693
694// return 0;
695// }
696
697
698#define MAX_CLIENTS 10
699#define BUFFER_SIZE 1024
700
707void kernel_chat(int num_args, ...) {
708 int network_fd;
709 struct sockaddr_in server_addr;
710 va_list args;
711
712 // 가변 인자 리스트 초기화
713 va_start(args, num_args);
714
715 const char *server_ip = va_arg(args, const char *); // 첫 번째 인자는 서버 IP
716 int port = va_arg(args, int); // 두 번째 인자는 포트
717
718 va_end(args); // 가변 인자 리스트 종료
719
720 // 네트워크 설정
721 network_fd = socket(AF_INET, SOCK_STREAM, 0); // 소켓 생성
722 if (network_fd < 0) {
723 perror("socket() 생성 실패");
724 kernel_printf("socket() 생성 실패\n");
725 exit(EXIT_FAILURE);
726 } else {
727 kernel_printf("socket() 생성 성공\n");
728
729 }
730
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); // 가변 인자로 받은 서버 IP
734 server_addr.sin_port = htons(port); // 가변 인자로 받은 포트
735
736 // 소켓 바인딩
737 if (bind(network_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
738 perror("bind() 실패");
739 close(network_fd);
740 exit(EXIT_FAILURE);
741 }
742
743 // 소켓 리스닝
744 if (listen(network_fd, MAX_CLIENTS) < 0) {
745 perror("listen() 실패");
746 close(network_fd);
747 exit(EXIT_FAILURE);
748 }
749 kernel_printf("서버가 포트 %d에서 대기 중입니다...\n", port);
750
751 // 소켓 포트 정보 조회
752 kernel_printf("현재 포트 %d 상태를 확인합니다.\n", port);
753 kernel_printf("**************************************************\n");
754 if (system("lsof -i :5100") != 0) {
755 perror("lsof 명령 실행 실패");
756 kernel_printf("lsof 명령 실행 실패\n");
757 close(network_fd);
758 exit(EXIT_FAILURE);
759 }
760 kernel_printf("**************************************************\n");
761
762 // 불필요한 변수들을 주석 처리하거나 삭제
763 // while (1) {
764 // socklen_t client_len = sizeof(client_addr);
765 // client_fd = accept(network_fd, (struct sockaddr *)&client_addr, &client_len);
766 // if (client_fd < 0) {
767 // perror("accept() 실패");
768 // continue;
769 // }
770 // printf("클라이언트가 연결되었습니다.\n");
771 // ssize_t nbytes;
772 // while ((nbytes = read(client_fd, buffer, sizeof(buffer))) > 0) {
773 // buffer[nbytes] = '\0';
774 // printf("클라이언트 메시지: %s\n", buffer);
775 // const char *response = "서버에서 수신했습니다.\n";
776 // write(client_fd, response, strlen(response));
777 // }
778 // printf("클라이언트 연결 종료\n");
779 // close(client_fd);
780 // }
781
782 // close(network_fd); // 네트워크 소켓 닫기
783}
void manual_server_mode()
수동 서버 관리 모드 함수
#define MAX_CLIENTS
main 함수
Definition kernel_chat.c:14
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)
클라이언트를 강제로 퇴장시키는 함수
#define BUFFER_SIZE
Definition kernel_chat.c:15
void log_chat_message(const char *message)
서버 측에서 발생한 채팅 메시지를 로그로 저장하는 함수
SmartPtr client_infos[MAX_CLIENTS]
클라이언트 정보를 스마트 포인터로 관리하는 배열
Definition kernel_chat.c:72
void daemonize()
daemonize 함수 구현
int create_network_tcp_process(int num_tcp_proc,...)
TCP 서버를 생성하고 클라이언트 연결을 처리하는 함수
void kill_room(int room_id)
클라이언트를 강제로 퇴장시키는 함수
void logo()
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)
클라이언트와의 통신을 처리하는 스레드 함수
#define DEFAULT_TCP_PORT
Definition kernel_chat.c:13
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)
클라이언트 정보를 담는 구조체
Definition kernel_chat.h:59
char username[BUFFER_SIZE]
Definition kernel_chat.h:63
pthread_mutex_t * client_mutex
Definition kernel_chat.h:64
공유 스마트 포인터
스마트 포인터 구조체
void * ptr
실제 메모리를 가리킴
고유 스마트 포인터