Toby's Study Blog
article thumbnail

๐Ÿ“ฌ ์†Œ์ผ“ ํ†ต์‹  ์ด๋ž€??

์•„๋ž˜ ๊ธ€์—์„œ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

https://toby12.tistory.com/52

 

[ubuntu] ์†Œ์ผ“ ํ†ต์‹  ๋ฐ์ดํ„ฐ ์ „์†ก ๋ฐ ์ €์žฅ

์†Œ์ผ“ ํ†ต์‹ ์ด๋ž€? ์šฐ์„  ์†Œ์ผ“์€ ๋‘ ๊ฐœ์˜ ์ปดํ“จํ„ฐ(์—”๋“œํฌ์ธํŠธ)๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ํ†ต๋กœ๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ ๋‘ ๊ฐœ์˜ ์ปดํ“จํ„ฐ๋Š” ์ด๋ฅผ ํ†ตํ•ด ๋„คํŠธ์›Œํฌ๊ฐ€ ํ˜•์„ฑ๋œ๋‹ค. ์œ„ ์ƒํƒœ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š” ํ†ต์‹ ์„ ํ•˜๋Š” ๊ฒƒ์„ ์†Œ

toby12.tistory.com

 

๐Ÿ“ฌ ์‹ค์Šต ๋ชฉํ‘œ

1. ์†Œ์ผ“ ํ†ต์‹ ์„ ์ด์šฉํ•œ ์ฑ„ํŒ… ํ”„๋กœ๊ทธ๋žจ ์ž‘์„ฑ

 

โ€ป ์ฑ„ํŒ… ์„œ๋ฒ„ โ€ป  

  1. ์„œ๋ฒ„ ์ดˆ๊ธฐํ™” ๋ฐ ์†Œ์ผ“ ์ƒ์„ฑ
    • ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ ํฌํŠธ ๋ฒˆํ˜ธ๋กœ ์„œ๋ฒ„ ์ดˆ๊ธฐํ™” ๋ฐ ์†Œ์ผ“์„ ์ƒ์„ฑ 
  2. ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ๋Œ€๊ธฐ ๋ฐ ์ธ์ฆ
    • accept ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ ์š”์ฒญ๋ฐ›์€ ํด๋ผ์ด์–ธํŠธ์˜ ์—ฐ๊ฒฐ 
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋˜๋ฉด, ID ๋ฐ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฐ›์•„ ์ธ์ฆ ์ˆ˜ํ–‰
  3. ํด๋ผ์ด์–ธํŠธ ๊ด€๋ฆฌ ๋ฐ ์“ฐ๋ ˆ๋“œ ์ƒ์„ฑ
    • ์ตœ๋Œ€ MAX_CLNT ๊ฐœ์ˆ˜๊นŒ์ง€์˜ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ด€๋ฆฌ
    • ์ƒˆ๋กœ์šด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋˜๋ฉด, ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํ•ด๋‹น ํด๋ผ์ด์–ธํŠธ์™€ ํ†ต์‹ ์„ ๋‹ด๋‹น
  4. ๋ฉ”์‹œ์ง€ ์ „์†ก
    • send_msg ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†ก
    • 'ALLMSG'๋ผ๋Š” ํŠน๋ณ„ํ•œ ์ˆ˜์‹ ์ž์—๊ฒŒ๋Š” ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†ก
    • 'IDLIST' ์ˆ˜์‹ ์ž์—๊ฒŒ๋Š” ํ˜„์žฌ ์„œ๋ฒ„์— ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์˜ ID ๋ชฉ๋ก์„ ์ „์†ก
  5. ์“ฐ๋ ˆ๋“œ ํ•จ์ˆ˜ (clnt_connection)
    • ํด๋ผ์ด์–ธํŠธ ์“ฐ๋ ˆ๋“œ ํ•จ์ˆ˜๋กœ, ํด๋ผ์ด์–ธํŠธ์™€์˜ ํ†ต์‹ ์„ ๋‹ด๋‹น
    • ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ , ์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „ํŒŒ

โ€ป ํด๋ผ์ด์–ธํŠธ โ€ป  

  1. ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ๋ฐ ์†Œ์ผ“ ์ƒ์„ฑ
    • ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ ์„œ๋ฒ„์˜ IP ์ฃผ์†Œ์™€ ํฌํŠธ ๋ฒˆํ˜ธ๋กœ ์„œ๋ฒ„์— ์†Œ์ผ“์„ ์ƒ์„ฑํ•˜์—ฌ ์—ฐ๊ฒฐ์„ ์‹œ๋„
  2. ์ธ์ฆ
    • ๋งค๊ฐœ๋ณ€์ˆ˜์— ์ง€์ •ํ•œ ์ด๋ฆ„์œผ๋กœ ์„œ๋ฒ„์— ์ ‘์†, ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ•จ๊ป˜ ์ „์†กํ•˜์—ฌ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•จ
  3. ๋ฉ”์‹œ์ง€ ์†ก์ˆ˜์‹ 
    • ์‚ฌ์šฉ์ž๋Š” ํ‚ค๋ณด๋“œ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•˜๊ณ , ์ด๋ฅผ ์„œ๋ฒ„์— ์ „์†ก
    • ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ์˜ ๋ฉ”์‹œ์ง€๋Š” ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ†ตํ•ด ์ˆ˜์‹ ๋˜์–ด ํ™”๋ฉด์— ์ถœ๋ ฅ๋จ
  4. ์“ฐ๋ ˆ๋“œ ํ•จ์ˆ˜ (send_msg, recv_msg)
    • ๊ฐ๊ฐ ๋ฉ”์‹œ์ง€ ์†ก์‹  ๋ฐ ์ˆ˜์‹ ์„ ๋‹ด๋‹นํ•˜๋Š” ์“ฐ๋ ˆ๋“œ ํ•จ์ˆ˜์ด๋‹ค. 
    • send_msg ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์„ ์ฝ์–ด ์„œ๋ฒ„๋กœ ์ „์†กํ•˜๊ณ 
    • recv_msg ํ•จ์ˆ˜๋Š” ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•˜์—ฌ ํ™”๋ฉด์— ์ถœ๋ ฅํ—˜

โ€ป ์ถ”๊ฐ€ ๋‚ด์šฉ โ€ป 

  • ์“ฐ๋ ˆ๋“œ ์‚ฌ์šฉ
    • ๊ฐ ํด๋ผ์ด์–ธํŠธ๋Š” ๋ณ„๋„์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌ๋˜๊ณ  ์ด๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ์™€ ๋™์‹œ์— ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • pthread ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ์„ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ๋ฎคํ…์Šค ์‚ฌ์šฉ
    • ์„œ๋ฒ„์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์—ฐ๊ฒฐ ๋ฐ ํ•ด์ œ์— ๋”ฐ๋ฅธ ๊ณต์œ  ์ž์› ์ ‘๊ทผ์„ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด ๋ฎคํ…์Šค๋ฅผ ์‚ฌ์šฉ
    • pthread_mutex_lock ๋ฐ pthread_mutex_unlock ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ ๊ด€๋ฆฌ
    • ์„œ๋ฒ„์—์„œ๋Š” ์ตœ๋Œ€ MAX_CLNT ๊ฐœ์˜ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ด€๋ฆฌ
    • ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ๋Š” CLIENT_INFO ๊ตฌ์กฐ์ฒด๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌ๋˜๋ฉฐ, ๊ฐ ํด๋ผ์ด์–ธํŠธ๋Š” ID, IP ์ฃผ์†Œ, ์†Œ์ผ“ ์‹๋ณ„์ž ๋“ฑ์„
      ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฉ”์‹œ์ง€ ์ „์†ก
    • ์„œ๋ฒ„์—์„œ๋Š” ํŠน์ • ์ˆ˜์‹ ์ž์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•˜๋Š” send_msg ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„
    • ์ˆ˜์‹ ์ž๊ฐ€ 'ALLMSG'์ธ ๊ฒฝ์šฐ์—๋Š” ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ „ํŒŒํ•˜๊ณ , 'IDLIST'์ธ ๊ฒฝ์šฐ์—๋Š”
      ํ˜„์žฌ ์ ‘์† ์ค‘์ธ ํด๋ผ์ด์–ธํŠธ์˜ ID ๋ชฉ๋ก์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

2. make ํŒŒ์ผ๋กœ ๋นŒ๋“œ

3. server, client ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰   

4. ๊ฒฐ๊ณผ ํ™•์ธ

๐Ÿ“ฌ ์‹ค์Šต ๊ฒฐ๊ณผ

์†Œ์ผ“ ํ†ต์‹ ์„ ์ด์šฉํ•œ ์ฑ„ํŒ… ํ”„๋กœ๊ทธ๋žจ ์ž‘์„ฑ

1. client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <signal.h>

#define BUF_SIZE 100
#define NAME_SIZE 20
#define ARR_CNT 5

char name[NAME_SIZE] = "[Default]";  // ํด๋ผ์ด์–ธํŠธ์˜ ์ด๋ฆ„
char msg[BUF_SIZE];  // ๋ฉ”์‹œ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฒ„ํผ

void *send_msg(void *arg);
void *recv_msg(void *arg);
void error_handling(char *msg);

int main(int argc, char *argv[]) {
    int sock;
    struct sockaddr_in serv_addr;
    pthread_t snd_thread, rcv_thread;
    void *thread_return;

    // ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ 4๊ฐœ๊ฐ€ ์•„๋‹ ์‹œ ์•ˆ๋‚ด ๋ฐ ์ข…๋ฃŒ(ํ”„๋กœ๊ทธ๋žจ, IP, ํฌํŠธ, ํด๋ผ์ด์–ธํŠธ ์ด๋ฆ„)
    if (argc != 4) {
        printf("Usage : %s <IP> <port> <name>\n", argv[0]);
        exit(1);
    }
    // ํด๋ผ์ด์–ธํŠธ ์ด๋ฆ„ ์„ค์ •
    sprintf(name, "%s", argv[3]);
    
    // ์†Œ์ผ“ ์ƒ์„ฑ
    sock = socket(PF_INET, SOCK_STREAM, 0);
    if (sock == -1)
        error_handling("socket() error");

    // ์„œ๋ฒ„ ์ฃผ์†Œ ์„ค์ •
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_addr.sin_port = htons(atoi(argv[2]));

    // ์„œ๋ฒ„์— ์—ฐ๊ฒฐ
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
        error_handling("connect() error");

    // ํด๋ผ์ด์–ธํŠธ์˜ ์ด๋ฆ„๊ณผ "PASSWD"๋ฅผ ์„œ๋ฒ„์— ์ „์†ก
    sprintf(msg, "[%s:PASSWD]", name);
    write(sock, msg, strlen(msg));

    // ์“ฐ๋ ˆ๋“œ ์ƒ์„ฑ ๋ฐ ์กฐ์ธ
    pthread_create(&rcv_thread, NULL, recv_msg, (void *)&sock);
    pthread_create(&snd_thread, NULL, send_msg, (void *)&sock);
    pthread_join(snd_thread, &thread_return);

    // ์†Œ์ผ“ ๋‹ซ์€ ํ›„ ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ
    close(sock);
    return 0;
}
// ๋ฉ”์‹œ์ง€๋ฅผ ์„œ๋ฒ„๋กœ ์ „์†กํ•˜๋Š” ํ•จ์ˆ˜
void *send_msg(void *arg) {
    int *sock = (int *)arg;
    int str_len;
    int ret;
    fd_set initset, newset;
    struct timeval tv;
    char name_msg[NAME_SIZE + BUF_SIZE + 2];

    // ํŒŒ์ผ ์ดˆ๊ธฐํ™”
    FD_ZERO(&initset);
    FD_SET(STDIN_FILENO, &initset);

    // ๋ฉ”์‹œ์ง€ ์ž…๋ ฅ ๋Œ€๊ธฐ
    fputs("Input a message! [ID]msg (Default ID:ALLMSG)\n", stdout);
    while (1) {
        memset(msg, 0, sizeof(msg));
        name_msg[0] = '\0';
        tv.tv_sec = 1;
        tv.tv_usec = 0;
        newset = initset;
        ret = select(STDIN_FILENO + 1, &newset, NULL, NULL, &tv);

        if (FD_ISSET(STDIN_FILENO, &newset)) {
            // ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€ ์ž…๋ ฅ ๋ฐ›์Œ
            fgets(msg, BUF_SIZE, stdin);
            // "quit"์„ ์ž…๋ ฅํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ ์†Œ์ผ“์„ ์ข…๋ฃŒ
            if (!strncmp(msg, "quit\n", 5)) {
                *sock = -1;
                return NULL;
            } else if (msg[0] != '[') {
                // ๋ฉ”์‹œ์ง€์˜ ์ฒซ ๊ธ€์ž๊ฐ€ '['์ด ์•„๋‹ˆ๋ฉด "[ALLMSG]"๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ „์†ก
                strcat(name_msg, "[ALLMSG]");
                strcat(name_msg, msg);
            } else
                strcpy(name_msg, msg);
            // ์„œ๋ฒ„๋กœ ๋ฉ”์‹œ์ง€ ์ „์†ก
            if (write(*sock, name_msg, strlen(name_msg)) <= 0) {
                *sock = -1;
                return NULL;
            }}
        if (ret == 0) {
            // ํƒ€์ž„์•„์›ƒ ๋ฐœ์ƒ ์‹œ
            if (*sock == -1)
                return NULL;
        }}}
// ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ํ•จ์ˆ˜
void *recv_msg(void *arg) {
    int *sock = (int *)arg;
    int i;
    char *pToken;
    char *pArray[ARR_CNT] = {0};
    char name_msg[NAME_SIZE + BUF_SIZE + 1];
    int str_len;

    while (1) {
        memset(name_msg, 0x0, sizeof(name_msg));
        str_len = read(*sock, name_msg, NAME_SIZE + BUF_SIZE);

        if (str_len <= 0) {
            // ์†Œ์ผ“์ด ๋‹ซํžŒ ๊ฒฝ์šฐ
            *sock = -1;
            return NULL;
        }
        name_msg[str_len] = 0;

        // ์ˆ˜์‹ ํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์ค€ ์ถœ๋ ฅ์— ์ถœ๋ ฅ
        fputs(name_msg, stdout);

        // ๋ฉ”์‹œ์ง€ ํŒŒ์‹ฑ 
        /*
        pToken = strtok(name_msg, "[:]");
        i = 0;
        while (pToken != NULL) {
            pArray[i] = pToken;
            if (++i >= ARR_CNT)
                break;
            pToken = strtok(NULL, "[:]");
        }
        printf("id:%s, msg:%s\n", pArray[0], pArray[1]);
        */
    }}
// ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ํ›„ ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•˜๋Š” ํ•จ์ˆ˜
void error_handling(char *msg) {
    fputs(msg, stderr);
    fputc('\n', stderr);
    exit(1);
}

 

2. server.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>

#define BUF_SIZE 100
#define MAX_CLNT 32
#define ID_SIZE 10
#define ARR_CNT 5
#define DEBUG

// ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ๋ฉ”์‹œ์ง€ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ์ฒด
typedef struct {
    char fd;
    char *from;
    char *to;
    char *msg;
    int len;
} MSG_INFO;
// ํด๋ผ์ด์–ธํŠธ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ์ฒด
typedef struct {
    int index;
    int fd;
    char ip[20];
    char id[ID_SIZE];
    char pw[ID_SIZE];
} CLIENT_INFO;

void *clnt_connection(void *arg);
void send_msg(MSG_INFO *msg_info, CLIENT_INFO *first_client_info);
void error_handling(char *msg);
void log_file(char *msgstr);

int clnt_cnt = 0;
pthread_mutex_t mutx;

int main(int argc, char *argv[]) {
    int serv_sock, clnt_sock;
    struct sockaddr_in serv_adr, clnt_adr;
    int clnt_adr_sz;
    int sock_option = 1;
    pthread_t t_id[MAX_CLNT] = {0};
    int str_len = 0;
    int i;
    char idpasswd[(ID_SIZE * 2) + 3];
    char *pToken;
    char *pArray[ARR_CNT] = {0};
    char msg[BUF_SIZE];

    // ๋ฏธ๋ฆฌ ๋“ฑ๋ก๋œ ํด๋ผ์ด์–ธํŠธ ์ •๋ณด
    CLIENT_INFO client_info[MAX_CLNT] = {{0, -1, "", "KHJ_LIN", "PASSWD"}, \
             {0,-1,"","KHJ_SQL","PASSWD"},  {0,-1,"","3","PASSWD"}, \
			 {0,-1,"","4","PASSWD"},  {0,-1,"","5","PASSWD"}, \
			 {0,-1,"","6","PASSWD"},  {0,-1,"","7","PASSWD"}, \
			 {0,-1,"","8","PASSWD"},  {0,-1,"","9","PASSWD"}, \
			 {0,-1,"","10","PASSWD"},  {0,-1,"","11","PASSWD"}, \
			 {0,-1,"","12","PASSWD"},  {0,-1,"","13","PASSWD"}, \
			 {0,-1,"","14","PASSWD"},  {0,-1,"","15","PASSWD"}, \
			 {0,-1,"","16","PASSWD"},  {0,-1,"","17","PASSWD"}, \
			 {0,-1,"","18","PASSWD"},  {0,-1,"","19","PASSWD"}, \
			 {0,-1,"","20","PASSWD"},  {0,-1,"","21","PASSWD"}, \
			 {0,-1,"","22","PASSWD"},  {0,-1,"","23","PASSWD"}, \
			 {0,-1,"","24","PASSWD"},  {0,-1,"","25","PASSWD"}, \
			 {0,-1,"","26","PASSWD"},  {0,-1,"","27","PASSWD"}, \
			 {0,-1,"","28","PASSWD"},  {0,-1,"","29","PASSWD"}, \
			 {0,-1,"","30","PASSWD"},  {0,-1,"","31","PASSWD"}, \
			 {0,-1,"","32","PASSWD"}};

    // ์ปค๋งจ๋“œ ๋ผ์ธ์—์„œ ํฌํŠธ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅ๋ฐ›์Œ
    if (argc != 2) {
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }
    fputs("IoT Server Start!!\n", stdout);

    // ๋ฎคํ…์Šค ์ดˆ๊ธฐํ™”
    if (pthread_mutex_init(&mutx, NULL))
        error_handling("mutex init error");

    // ์†Œ์ผ“ ์ƒ์„ฑ
    serv_sock = socket(PF_INET, SOCK_STREAM, 0);

    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));

    // ์†Œ์ผ“ ์˜ต์…˜ ์„ค์ •
    setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_option, sizeof(sock_option));

    // ์†Œ์ผ“ ๋ฐ”์ธ๋”ฉ
    if (bind(serv_sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) == -1)
        error_handling("bind() error");

    // ์†Œ์ผ“ ๋ฆฌ์Šค๋‹
    if (listen(serv_sock, 5) == -1)
        error_handling("listen() error");

    while (1) {
        clnt_adr_sz = sizeof(clnt_adr);
        clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &clnt_adr_sz);
        if (clnt_cnt >= MAX_CLNT) {
            printf("socket full\n");
            shutdown(clnt_sock, SHUT_WR);
            continue;
        } else if (clnt_sock < 0) {
            perror("accept()");
            continue;
        }
        // ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ID์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ฝ์Œ
        str_len = read(clnt_sock, idpasswd, sizeof(idpasswd));
        idpasswd[str_len] = '\0';

        if (str_len > 0) {
            i = 0;
            pToken = strtok(idpasswd, "[:]");
            while (pToken != NULL) {
                pArray[i] = pToken;
                if (i++ >= ARR_CNT)
                    break;
                pToken = strtok(NULL, "[:]");
            }
            for (i = 0; i < MAX_CLNT; i++) {
                if (!strcmp(client_info[i].id, pArray[0])) {
                    if (client_info[i].fd != -1) {
                        // ์ด๋ฏธ ๋กœ๊ทธ์ธ๋œ ID์ธ ๊ฒฝ์šฐ
                        sprintf(msg, "[%s] Already logged!\n", pArray[0]);
                        write(clnt_sock, msg, strlen(msg));
                        log_file(msg);
                        shutdown(clnt_sock, SHUT_WR);
#if 1   // for MCU
                        shutdown(client_info[i].fd, SHUT_WR);
                        client_info[i].fd = -1;
#endif
                        break;
                    }
                    if (!strcmp(client_info[i].pw, pArray[1])) {
                        // ID์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ
                        strcpy(client_info[i].ip, inet_ntoa(clnt_adr.sin_addr));
                        pthread_mutex_lock(&mutx);
                        client_info[i].index = i;
                        client_info[i].fd = clnt_sock;
                        clnt_cnt++;
                        pthread_mutex_unlock(&mutx);
                        sprintf(msg, "[%s] New connected! (ip:%s,fd:%d,sockcnt:%d)\n",
                                pArray[0], inet_ntoa(clnt_adr.sin_addr), clnt_sock, clnt_cnt);
                        log_file(msg);
                        write(clnt_sock, msg, strlen(msg));
                        pthread_create(t_id + i, NULL, clnt_connection, (void *)(client_info + i));
                        pthread_detach(t_id[i]);
                        break;
                    }}}
            if (i == MAX_CLNT) {
                // ์ธ์ฆ ์‹คํŒจํ•œ ๊ฒฝ์šฐ
                sprintf(msg, "[%s] Authentication Error!\n", pArray[0]);
                write(clnt_sock, msg, strlen(msg));
                log_file(msg);
                shutdown(clnt_sock, SHUT_WR);
            }
        } else {
            // ์ฝ๊ธฐ ์‹คํŒจํ•œ ๊ฒฝ์šฐ
            shutdown(clnt_sock, SHUT_WR);
        }}
    return 0;
}
// ํด๋ผ์ด์–ธํŠธ ์“ฐ๋ ˆ๋“œ ํ•จ์ˆ˜
void *clnt_connection(void *arg) {
    CLIENT_INFO *client_info = (CLIENT_INFO *)arg;
    int str_len = 0;
    int index = client_info->index;
    char msg[BUF_SIZE];
    char to_msg[MAX_CLNT * ID_SIZE + 1];
    int i = 0;
    char *pToken;
    char *pArray[ARR_CNT] = {0};
    char strBuff[130] = {0};

    // ๋ฉ”์‹œ์ง€ ์ •๋ณด ๊ตฌ์กฐ์ฒด ๋ฐ ์ฒซ ๋ฒˆ์งธ ํด๋ผ์ด์–ธํŠธ ์ •๋ณด ์„ค์ •
    MSG_INFO msg_info;
    CLIENT_INFO *first_client_info;

    first_client_info = (CLIENT_INFO *)((void *)client_info - (void *)(sizeof(CLIENT_INFO) * index));

    // ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์–ด์˜ด
    while (1) {
        memset(msg, 0x0, sizeof(msg));
        str_len = read(client_info->fd, msg, sizeof(msg) - 1);

        if (str_len <= 0)
            break;
        msg[str_len] = '\0';
        pToken = strtok(msg, "[:]");
        i = 0;
        while (pToken != NULL) {
            pArray[i] = pToken;
            if (i++ >= ARR_CNT)
                break;
            pToken = strtok(NULL, "[:]");
        }
        // ๋ฉ”์‹œ์ง€ ์ •๋ณด ์„ค์ •
        msg_info.fd = client_info->fd;
        msg_info.from = client_info->id;
        msg_info.to = pArray[0];
        sprintf(to_msg, "[%s]%s", msg_info.from, pArray[1]);
        msg_info.msg = to_msg;
        msg_info.len = strlen(to_msg);

        sprintf(strBuff, "msg : [%s->%s] %s", msg_info.from, msg_info.to, pArray[1]);
        log_file(strBuff);
        // ๋ฉ”์‹œ์ง€ ์ „์†ก
        send_msg(&msg_info, first_client_info);
    }
    // ํด๋ผ์ด์–ธํŠธ ์†Œ์ผ“ ์ข…๋ฃŒ
    close(client_info->fd);
    sprintf(strBuff, "Disconnect ID:%s (ip:%s,fd:%d,sockcnt:%d)\n", client_info->id,
            client_info->ip, client_info->fd, clnt_cnt - 1);
    log_file(strBuff);

    // ๋ฎคํ…์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์นด์šดํŠธ ๊ฐฑ์‹ 
    pthread_mutex_lock(&mutx);
    clnt_cnt--;
    client_info->fd = -1;
    pthread_mutex_unlock(&mutx);

    return 0;
}
// ๋ฉ”์‹œ์ง€ ์ „์†ก ํ•จ์ˆ˜
void send_msg(MSG_INFO *msg_info, CLIENT_INFO *first_client_info) {
    int i = 0;

    if (!strcmp(msg_info->to, "ALLMSG")) {
        // ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฉ”์‹œ์ง€ ์ „์†ก
        for (i = 0; i < MAX_CLNT; i++)
            if ((first_client_info + i)->fd != -1)
                write((first_client_info + i)->fd, msg_info->msg, msg_info->len);
    } else if (!strcmp(msg_info->to, "IDLIST")) {
        // ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์˜ ID ๋ชฉ๋ก์„ ์ „์†ก
        char *idlist = (char *)malloc(ID_SIZE * MAX_CLNT);
        msg_info->msg[strlen(msg_info->msg) - 1] = '\0';
        strcpy(idlist, msg_info->msg);

        for (i = 0; i < MAX_CLNT; i++) {
            if ((first_client_info + i)->fd != -1) {
                strcat(idlist, (first_client_info + i)->id);
                strcat(idlist, " ");
            }}
        strcat(idlist, "\n");
        write(msg_info->fd, idlist, strlen(idlist));
        free(idlist);
    } else {
        // ํŠน์ • ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฉ”์‹œ์ง€ ์ „์†ก
        for (i = 0; i < MAX_CLNT; i++)
            if ((first_client_info + i)->fd != -1)
                if (!strcmp(msg_info->to, (first_client_info + i)->id))
                    write((first_client_info + i)->fd, msg_info->msg, msg_info->len);
    }}
// ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ํ•จ์ˆ˜
void error_handling(char *msg) {
    fputs(msg, stderr);
    fputc('\n', stderr);
    exit(1);
}
// ๋กœ๊ทธ ํŒŒ์ผ์— ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ํ•จ์ˆ˜
void log_file(char *msgstr) {
    fputs(msgstr, stdout);
}

 

make ํŒŒ์ผ๋กœ ๋นŒ๋“œ

1. make ํŒŒ์ผ ์ž‘์„ฑ

# ์ปดํŒŒ์ผ๋Ÿฌ ์„ค์ •
CC := gcc

# ์‹คํ–‰ ํŒŒ์ผ ์ด๋ฆ„
TARGET_SRV := chat_server
TARGET_CLN := chat_client

# ๋งํฌ ๋ฐ ์Šค๋ ˆ๋”ฉ ํ”Œ๋ž˜๊ทธ
LDFLAGS := -D_REENTRANT -pthread

# ์†Œ์Šค ํŒŒ์ผ
SRV_SOURCES := chat_server.c
CLN_SOURCES := chat_client.c

# ๋ชฉ์  ํŒŒ์ผ
SRV_OBJECTS := $(SRV_SOURCES:.c=.o)
CLN_OBJECTS := $(CLN_SOURCES:.c=.o)

# ๋ชจ๋“  ๋ชฉํ‘œ ํŒŒ์ผ ๋นŒ๋“œ ๊ทœ์น™
all: $(TARGET_SRV) $(TARGET_CLN)

# chat_server ์‹คํ–‰ ํŒŒ์ผ ๋นŒ๋“œ ๊ทœ์น™
$(TARGET_SRV): $(SRV_OBJECTS)
	$(CC) -o $@ $(SRV_OBJECTS) $(LDFLAGS)

# chat_client ์‹คํ–‰ ํŒŒ์ผ ๋นŒ๋“œ ๊ทœ์น™
$(TARGET_CLN): $(CLN_OBJECTS)
	$(CC) -o $@ $(CLN_OBJECTS) $(LDFLAGS)

# ๊ฐœ๋ณ„ ์†Œ์Šค ํŒŒ์ผ์„ ๋ชฉ์  ํŒŒ์ผ๋กœ ์ปดํŒŒ์ผ ๊ทœ์น™
%.o: %.c
	$(CC) -c -o $@ $<

# ๋ชฉ์  ํŒŒ์ผ ๋ฐ ์‹คํ–‰ ํŒŒ์ผ ์ •๋ฆฌ ๊ทœ์น™
clean:
	rm -f *.o $(TARGET_SRV) $(TARGET_CLN)

# ๋ชจ๋“  ํŒŒ์ผ, ์‹คํ–‰ ํŒŒ์ผ ํฌํ•จ ์ •๋ฆฌ ๊ทœ์น™
clean_all:
	rm -f *.o $(TARGET_SRV) $(TARGET_CLN)


2. ๋นŒ๋“œ ๊ฒฐ๊ณผ

server, client ๋ชจ๋‘ ์„ฑ๊ณต์ ์œผ๋กœ ๋นŒ๋“œ๋จ 

cleint, server ๋นŒ๋“œ ๊ฒฐ๊ณผ

server, client ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰   

1. server ์‹คํ–‰

ํ”„๋กœ๊ทธ๋žจ + ํฌํŠธ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ์„œ๋ฒ„ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰

2. client ์‹คํ–‰

ํ”„๋กœ๊ทธ๋žจ + ์„œ๋ฒ„ ip + ํฌํŠธ ๋ฒˆํ˜ธ + ๋“ฑ๋ก๋œ ์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ 

๊ฒฐ๊ณผ ํ™•์ธ 

  1. ๋“ฑ๋ก๋œ ID๋กœ ํด๋ผ์ด์–ธํŠธ ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜์—ฌ ์„ฑ๊ณต์ ์œผ๋กœ ์„œ๋ฒ„์™€ ์—ฐ๊ฒฐ๋˜๊ณ 
    ์„œ๋ฒ„์— ํ•ด๋‹น ๊ณ„์ • ์ ‘์†๋จ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜์—ˆ์Œ  
  2. ํด๋ผ์ด์–ธํŠธ์—์„œ ์ „์ฒด ์ฑ„ํŒ… ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ธ ๊ฒฐ๊ณผ ์„œ๋ฒ„ ๋ฐ ์ž์‹ ์˜ ํด๋ผ์ด์–ธํŠธ์— ํ•ด๋‹น ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜์—ˆ์Œ
  3. ํด๋ผ์ด์–ธํŠธ์—์„œ ์—ฐ๊ฒฐ์„ ์ข…๋ฃŒ์‹œ ์„œ๋ฒ„์—์„œ Disconnect ID : KHJ_LIN + ip ์ฃผ์†Œ ์ถœ๋ ฅ๋จ

์„œ๋ฒ„์—์„œ ์ฑ„ํŒ… ๋ฐ›์€ ํ›„ ํ™”๋ฉด์— ์ถœ๋ ฅ ์ดํ›„ ๋‹ค์‹œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด๋ƒ„
ํด๋ผ์ด์–ธํŠธ์—์„œ ์ฑ„ํŒ… ๋ณด๋ƒ„
์—ฐ๊ฒฐ ์ข…๋ฃŒ์‹œ ์„œ๋ฒ„ ๋ฉ”์‹œ์ง€

profile

Toby's Study Blog

@Toby12

ํฌ์ŠคํŒ…์ด ์ข‹์•˜๋‹ค๋ฉด "์ข‹์•„์š”โค๏ธ" ๋˜๋Š” "๊ตฌ๋…๐Ÿ‘๐Ÿป" ํ•ด์ฃผ์„ธ์š”!

๊ฒ€์ƒ‰ ํƒœ๊ทธ