본문 바로가기
C

[C] 파이프를 사용한 단체방 채팅 서버 만들기

by 돌맹96 2023. 12. 3.
728x90
반응형
  • 서버는 클라이언트 접속용 server pipe file을 생성하고 기다린다.
  • 클라이언트는 server pipe file을 사용하여 클라이언트 접속을 서버에게 알린다.
  • 이때 클라이언트가 생성한 client pipe file 이름을 포함한 클라이언트 정보를 서버에게 알려준다.
  • 서버는 client pipe file 을 open하고 클라이언트 목록에 방금 접속한 클라이언트 정보를 추가한다.(클라이언트 이름, client pipe file descriptor)
  • 서버는 클라이언트가 접속할 때마다 클라이언트 정보를 화면에 출력한다.
  • 서버에 접속한 클라이언트 중 하나가 메시지를 입력하면 서버는 해당 메시지를 모든 클라이언트에게 전달한다.
  • 클라이언트는 서버로부터 메시지를 받으면 화면에 해당 메시지를 출력한다
  • 파이프는 1:N 통신이 가능하다.
  • 클라이언트는 자식 프로세스를 생성해서 서버로 부터 오는 메시지를 받는 역할만 수행하도록 구현할 수 있다. -> 부모 프로세스는 사용자의 입력 메시지를 서버에 전달하는 역할만 수행한다.
  • 파이프를 open()  , O_RDONLY O_WRONLY 옵션을 주게되면 통신할 프로세스가 사라질 경우 또는 통신하는 상대방이 파이프를 close() 경우 read() write()에서 0이나 -1 리턴됨. 이를 통해 클라이언트 접속이 끊김을 확인할  있음.

 

 

* 클라이언트 코드

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#define SERVER_PIPE "/tmp/server_pipe"
#define CLIENT_PIPE "/tmp/client_%d_pipe"

int main() {
    int pid = getpid();
    char client_pipe[100];
    sprintf(client_pipe, CLIENT_PIPE, pid);
    mkfifo(client_pipe, 0666);

    int server_fd = open(SERVER_PIPE, O_WRONLY);
    char buffer[300];
    sprintf(buffer, "CONNECT %s", client_pipe);
    write(server_fd, buffer, strlen(buffer) + 1);

    pid_t child_pid = fork();
    if (child_pid == 0) {  // Child process
        int client_fd = open(client_pipe, O_RDONLY);
        while (1) {
            ssize_t count = read(client_fd, buffer, sizeof(buffer));
            if (count <= 0) {  // Connection lost
                printf("Connection lost. Exiting.\n");
                break;
            }
            printf("Received message: %s\n", buffer);
        }
        close(client_fd);
        exit(0);
    } else {  // Parent process
        while (1) {
            fgets(buffer, sizeof(buffer), stdin);
            write(server_fd, buffer, strlen(buffer) + 1);
        }
    }

    close(server_fd);
    unlink(client_pipe);
    return 0;
}

 

* 서버 코드

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#define SERVER_PIPE "/tmp/server_pipe"
#define CLIENT_PIPE "/tmp/client_%d_pipe"

typedef struct {
    char name[100];
    int fd;
} Client;

Client clients[10];
int client_count = 0;

void broadcast_message(const char *message) {
    for (int i = 0; i < client_count; i++) {
        write(clients[i].fd, message, strlen(message) + 1);
    }
}

int main() {
    mkfifo(SERVER_PIPE, 0666);
    int server_fd = open(SERVER_PIPE, O_RDONLY);
    char buffer[300];

    while (1) {
        read(server_fd, buffer, sizeof(buffer));
        if (strncmp("CONNECT", buffer, 7) == 0) {
            char client_pipe[100];
            sscanf(buffer, "CONNECT %s", client_pipe);
            int client_fd = open(client_pipe, O_WRONLY);

            Client new_client;
            strcpy(new_client.name, client_pipe);
            new_client.fd = client_fd;
            clients[client_count++] = new_client;

            printf("New client connected: %s\n", new_client.name);
        } else {
            printf("Received message: %s\n", buffer);
            broadcast_message(buffer);
        }
    }

    close(server_fd);
    unlink(SERVER_PIPE);
    return 0;
}
728x90
반응형