5 minute read

๐Ÿ“–

๐Ÿ„ Server ์ฝ”๋“œ

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <WinSock2.h>
#include <process.h>
#include <string.h>

// ํ•จ์ˆ˜ ๋ฐ ๋ณ€์ˆ˜์˜ ์„ ์–ธ
int server_init();
int server_close();
unsigned int WINAPI do_chat_service(void* param);
unsigned int WINAPI recv_and_forward(void* param);
int add_client(int index);
int read_client(int index);
void remove_client(int index);
int notify_client(char* message);
char* get_client_ip(int index);

// ํด๋ผ์ด์–ธํŠธ ์†Œ์ผ“ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ์ฒด
typedef struct sock_info
{
    SOCKET s;
    HANDLE ev;
    char nick[50];
    char ipaddr[50];
} SOCK_INFO;

// ํฌํŠธ ๋ฒˆํ˜ธ์™€ ํด๋ผ์ด์–ธํŠธ ์ˆ˜์— ๋Œ€ํ•œ ์ƒ์ˆ˜ ์ •์˜
int port_number = 9999;
const int client_count = 10;
SOCK_INFO sock_array[client_count + 1]; // ํด๋ผ์ด์–ธํŠธ ์ •๋ณด๋ฅผ ๋‹ด๋Š” ๋ฐฐ์—ด
int total_socket_count = 0; // ํ˜„์žฌ ์—ฐ๊ฒฐ๋œ ์†Œ์ผ“์˜ ์ˆ˜

// ๋ฉ”์ธ ํ•จ์ˆ˜
int main(int argc, char* argv[])
{
    unsigned int tid;
    char message[MAXBYTE] = "";
    HANDLE mainthread;

    printf("\n์‚ฌ์šฉ๋ฒ• : mcodes_server [ํฌํŠธ๋ฒˆํ˜ธ]\n");
    printf("         ex) mcodes_server.exe 9999\n");
    printf("         ex) mcodes_server.exe \n\n");

    if (argv[1] != NULL)
        port_number = atoi(argv[1]);

    // ์„œ๋ฒ„ ์“ฐ๋ ˆ๋“œ ์‹œ์ž‘
    mainthread = (HANDLE)_beginthreadex(NULL, 0, do_chat_service, (void*)0, 0, &tid);
    if (mainthread)
    {
        while (1)
        {
            gets_s(message, MAXBYTE);
            if (strcmp(message, "/x") == 0)
                break;

            notify_client(message);
        }
        // ์„œ๋ฒ„ ์ข…๋ฃŒ
        server_close();
        WSACleanup();
        CloseHandle(mainthread);
    }

    return 0;
}

// ์„œ๋ฒ„ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
int server_init()
{
    WSADATA wsadata;
    SOCKET s;
    SOCKADDR_IN server_address;

    memset(&sock_array, 0, sizeof(sock_array));
    total_socket_count = 0;
    if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
    {
        puts("WSAStartup ์—๋Ÿฌ.");
        return -1;
    }

    if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
        puts("socket ์—๋Ÿฌ.");
        return -1;
    }

    memset(&server_address, 0, sizeof(server_address));
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(port_number);

    if (bind(s, (struct sockaddr*)&server_address, sizeof(server_address)) < 0)
    {
        puts("bind ์—๋Ÿฌ");
        return -2;
    }

    if (listen(s, SOMAXCONN) < 0)
    {
        puts("listen ์—๋Ÿฌ");
        return -3;
    }

    return s;
}

// ์„œ๋ฒ„ ์ข…๋ฃŒ ํ•จ์ˆ˜
int server_close()
{
    for (int i = 1; i < total_socket_count; i++)
    {
        closesocket(sock_array[i].s);
        WSACloseEvent(sock_array[i].ev);
    }

    return 0;
}

// ํด๋ผ์ด์–ธํŠธ์™€์˜ ํ†ต์‹ ์„ ๋‹ด๋‹นํ•˜๋Š” ํ•จ์ˆ˜
unsigned int WINAPI do_chat_service(void* param)
{
    SOCKET server_socket;
    WSANETWORKEVENTS ev;
    int index;
    WSAEVENT handle_array[client_count + 1];

    // ์„œ๋ฒ„ ์ดˆ๊ธฐํ™”
    server_socket = server_init();
    if (server_socket < 0)
    {
        printf("์ดˆ๊ธฐํ™” ์—๋Ÿฌ\n");
        exit(0);
    }
    else
    {
        printf("\n >> ์„œ๋ฒ„ ์ดˆ๊ธฐํ™”๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. (ํฌํŠธ๋ฒˆํ˜ธ:%d)\n", port_number);

        HANDLE event = WSACreateEvent();
        sock_array[total_socket_count].ev = event;
        sock_array[total_socket_count].s = server_socket;
        strcpy_s(sock_array[total_socket_count].nick, "svr");
        strcpy_s(sock_array[total_socket_count].ipaddr, "0.0.0.0");

        WSAEventSelect(server_socket, event, FD_ACCEPT);
        total_socket_count++;

        while (true)
        {
            memset(&handle_array, 0, sizeof(handle_array));
            for (int i = 0; i < total_socket_count; i++)
                handle_array[i] = sock_array[i].ev;

            index = WSAWaitForMultipleEvents(total_socket_count, handle_array, false, INFINITE, false);
            if ((index != WSA_WAIT_FAILED) && (index != WSA_WAIT_TIMEOUT))
            {
                WSAEnumNetworkEvents(sock_array[index].s, sock_array[index].ev, &ev);
                if (ev.lNetworkEvents == FD_ACCEPT)
                    add_client(index);
                else if (ev.lNetworkEvents == FD_READ)
                    read_client(index);
                else if (ev.lNetworkEvents == FD_CLOSE)
                    remove_client(index);
            }
        }
        closesocket(server_socket);
    }

    WSACleanup();
    _endthreadex(0);

    return 0;
}

// ํด๋ผ์ด์–ธํŠธ ์ถ”๊ฐ€ ํ•จ์ˆ˜
int add_client(int index)
{
    SOCKADDR_IN addr;
    int len = 0;
    SOCKET accept_sock;

    if (total_socket_count == FD_SETSIZE)
        return 1;
    else {

        len = sizeof(addr);
        memset(&addr, 0, sizeof(addr));
        accept_sock = accept(sock_array[0].s, (SOCKADDR*)&addr, &len);

        HANDLE event = WSACreateEvent();
        sock_array[total_socket_count].ev = event;
        sock_array[total_socket_count].s = accept_sock;
        strcpy_s(sock_array[total_socket_count].ipaddr, inet_ntoa(addr.sin_addr));

        WSAEventSelect(accept_sock, event, FD_READ | FD_CLOSE);

        total_socket_count++;
        printf(" >> ์‹ ๊ทœ ํด๋ผ์ด์–ธํŠธ ์ ‘์†(IP : %s)\n", inet_ntoa(addr.sin_addr));

        char msg[256];
        sprintf_s(msg, " >> ์‹ ๊ทœ ํด๋ผ์ด์–ธํŠธ ์ ‘์†(IP : %s)\n", inet_ntoa(addr.sin_addr));
        notify_client(msg);
    }

    return 0;
}

// ํด๋ผ์ด์–ธํŠธ ์ฝ๊ธฐ ํ•จ์ˆ˜
int read_client(int index)
{
    unsigned int tid;
    HANDLE mainthread = (HANDLE)_beginthreadex(NULL, 0, recv_and_forward, (void*)index, 0, &tid);
    WaitForSingleObject(mainthread, INFINITE);

    CloseHandle(mainthread);

    return 0;
}

// ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹  ๋ฐ ์ „๋‹ฌ ํ•จ์ˆ˜
unsigned int WINAPI recv_and_forward(void* param)
{
    int index = (int)param;
    char message[MAXBYTE], share_message[MAXBYTE];
    SOCKADDR_IN client_address;
    int recv_len = 0, addr_len = 0;
    char* token1 = NULL;
    char* next_token = NULL;

    memset(&client_address, 0, sizeof(client_address));

    if ((recv_len = recv(sock_array[index].s, message, MAXBYTE, 0)) > 0)
    {
        addr_len = sizeof(client_address);
        getpeername(sock_array[index].s, (SOCKADDR*)&client_address, &addr_len);
        strcpy_s(share_message, message);

        if (strlen(sock_array[index].nick) <= 0)
        {
            token1 = strtok_s(message, "]", &next_token);
            strcpy_s(sock_array[index].nick, token1 + 1);
        }
        for (int i = 1; i < total_socket_count; i++)
            send(sock_array[i].s, share_message, MAXBYTE, 0);
    }

    _endthreadex(0);
    return 0;
}

// ํด๋ผ์ด์–ธํŠธ ์ œ๊ฑฐ ํ•จ์ˆ˜
void remove_client(int index)
{
    char remove_ip[256];
    char message[MAXBYTE];

    strcpy_s(remove_ip, get_client_ip(index));
    printf(" >> ํด๋ผ์ด์–ธํŠธ ์ ‘์† ์ข…๋ฃŒ(Index: %d, IP: %s, ๋ณ„๋ช…: %s)\n", index, remove_ip, sock_array[index].nick);
    sprintf_s(message, " >> ํด๋ผ์ด์–ธํŠธ ์ ‘์† ์ข…๋ฃŒ(IP: %s, ๋ณ„๋ช…: %s)\n", remove_ip, sock_array[index].nick);

    closesocket(sock_array[index].s);
    WSACloseEvent(sock_array[index].ev);

    total_socket_count--;
    sock_array[index].s = sock_array[total_socket_count].s;
    sock_array[index].ev = sock_array[total_socket_count].ev;
    strcpy_s(sock_array[index].ipaddr, sock_array[total_socket_count].ipaddr);
    strcpy_s(sock_array[index].nick, sock_array[total_socket_count].nick);

    notify_client(message);
}

// ํด๋ผ์ด์–ธํŠธ IP ์ฃผ์†Œ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
char* get_client_ip(int index)
{
    static char ipaddress[256];
    int addr_len;
    struct sockaddr_in sock;

    addr_len = sizeof(sock);
    if (getpeername(sock_array[index].s, (struct sockaddr*)&sock, &addr_len) < 0)
        return NULL;

    strcpy_s(ipaddress, inet_ntoa(sock.sin_addr));
    return ipaddress;
}

// ํด๋ผ์ด์–ธํŠธ์— ๋ฉ”์‹œ์ง€ ์•Œ๋ฆฌ๋Š” ํ•จ์ˆ˜
int notify_client(char* message)
{
    for (int i = 1; i < total_socket_count; i++)
        send(sock_array[i].s, message, MAXBYTE, 0);

    return 0;
}


๐Ÿ„ Client ์ฝ”๋“œ

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <WinSock2.h>
#include <process.h>
#include <string.h>

// ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜ ์„ ์–ธ
int client_init(char* ip, int port);
// ์ฑ„ํŒ… ์„œ๋น„์Šค ํ•จ์ˆ˜ ์„ ์–ธ
unsigned int WINAPI do_chat_service(void* param);

// ๋ฉ”์ธ ํ•จ์ˆ˜
int main(int argc, char* argv[])
{
    char ip_addr[256] = "127.0.0.1";
    int port_number = 9999;
    char nickname[50] = "๋ฐฉ๋‚จํ˜„";
    unsigned int tid;
    int sock;
    char input[MAXBYTE] = "";
    char message[MAXBYTE] = "";
    char* pexit = NULL;
    HANDLE mainthread;

    // ์ปค๋งจ๋“œ๋ผ์ธ ์ธ์ˆ˜๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์‚ฌ์šฉ๋ฒ• ์ถœ๋ ฅ ํ›„ ์ข…๋ฃŒ
    //if (argc < 4)
    //{
    //    printf("\n์‚ฌ์šฉ๋ฒ• : mcodes_client [์„œ๋ฒ„์ฃผ์†Œ] [ํฌํŠธ๋ฒˆํ˜ธ] [๋‹‰๋„ค์ž„]\n\n");
    //    printf("        ex) mcodes_client.exe 192.168.100.100 9999 mainCodes\n");
    //    exit(0);
    //}

    // ์ปค๋งจ๋“œ๋ผ์ธ ์ธ์ˆ˜์—์„œ ์„œ๋ฒ„ ์ฃผ์†Œ, ํฌํŠธ ๋ฒˆํ˜ธ, ๋‹‰๋„ค์ž„์„ ๊ฐ€์ ธ์˜ด
    if (argv[1] != NULL && argv[2] != NULL && argv[3] != NULL)
    {
        strcpy_s(ip_addr, argv[1]);  // ์„œ๋ฒ„ ์ฃผ์†Œ
        port_number = atoi(argv[2]); // ํฌํŠธ ๋ฒˆํ˜ธ
        strcpy_s(nickname, argv[3]); // ๋‹‰๋„ค์ž„
    }

    // ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
    sock = client_init(ip_addr, port_number);
    if (sock < 0)
    {
        printf("sock_init ์—๋Ÿฌ\n");
        exit(0);
    }

    // ์ฑ„ํŒ… ์„œ๋น„์Šค ์“ฐ๋ ˆ๋“œ ์‹œ์ž‘
    mainthread = (HANDLE)_beginthreadex(NULL, 0, do_chat_service, (void*)sock, 0, &tid);
    if (mainthread)
    {
        while (1)
        {
            gets_s(input, MAXBYTE);
            sprintf_s(message, "[%s] %s", nickname, input);
            send(sock, message, sizeof(message), 0);
            pexit = strrchr(message, '/');
            if (pexit)
                if (strcmp(pexit, "/x") == 0)
                    break;
        }

        closesocket(sock);
        WSACleanup();
        CloseHandle(mainthread);
    }

    return 0;
}

// ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
int client_init(char* ip, int port)
{
    SOCKET server_socket;
    WSADATA wsadata;
    SOCKADDR_IN server_address = { 0 };

    // Winsock ์ดˆ๊ธฐํ™”
    if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
    {
        printf("WSAStartup ์—๋Ÿฌ\n");
        return -1;
    }

    // ์†Œ์ผ“ ์ƒ์„ฑ
    if ((server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
        puts("socket ์—๋Ÿฌ.");
        return -1;
    }

    // ์„œ๋ฒ„ ์ฃผ์†Œ ์„ค์ •
    memset(&server_address, 0, sizeof(server_address));
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = inet_addr(ip);
    server_address.sin_port = htons(port);

    // ์„œ๋ฒ„์— ์—ฐ๊ฒฐ
    if ((connect(server_socket, (struct sockaddr*)&server_address, sizeof(server_address))) < 0)
    {
        puts("connect ์—๋Ÿฌ.");
        return -1;
    }

    return server_socket;
}

// ์ฑ„ํŒ… ์„œ๋น„์Šค ํ•จ์ˆ˜
unsigned int WINAPI do_chat_service(void* params)
{
    SOCKET s = (SOCKET)params;
    char recv_message[MAXBYTE];
    int len = 0;
    int index = 0;
    WSANETWORKEVENTS ev;
    HANDLE event = WSACreateEvent();

    // ์†Œ์ผ“ ์ด๋ฒคํŠธ ์„ค์ •
    WSAEventSelect(s, event, FD_READ | FD_CLOSE);
    while (1)
    {
        index = WSAWaitForMultipleEvents(1, &event, false, INFINITE, false);
        if ((index != WSA_WAIT_FAILED) && (index != WSA_WAIT_TIMEOUT))
        {
            WSAEnumNetworkEvents(s, event, &ev);
            if (ev.lNetworkEvents == FD_READ)
            {
                int len = recv(s, recv_message, MAXBYTE, 0);
                if (len > 0)
                    printf("%s\n", recv_message);
            }
            else if (ev.lNetworkEvents == FD_CLOSE)
            {
                printf(" >> ์„œ๋ฒ„ ์„œ๋น„์Šค๊ฐ€ ์ค‘๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. (์ข…๋ฃŒ: \"/x\")\n");
                closesocket(s);
                break;
            }
        }
    }
    WSACleanup();
    _endthreadex(0);

    return 0;
}



๊ฐœ์ธ ๊ณต๋ถ€ ๊ธฐ๋ก์šฉ ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.
ํ‹€๋ฆฌ๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ์ œ๋ณดํ•ด์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.๐Ÿ˜