[Basic]Socket

๐Ÿ‘‰๐Ÿป ๊ธฐ๋ณธ์ ์ธ ์†Œ์ผ“์— ๋Œ€ํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค.
This is an explanation of basic sockets.

๐Ÿ‘‰๐Ÿป Echo Server๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ณด๋‚ธ ๋ฉ”์„ธ์ง€๋ฅผ ์„œ๋ฒ„๊ฐ€ ๋‹ค์‹œ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ณด๋‚ด๋Š” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
Echo Server is simple code that sends a message sent from a client back to the client.

๐Ÿ‘‰๐Ÿป Thread Server๋Š” ์•„์ฃผ ๊ธฐ๋ณธ์ ์ธ ์ฑ„ํŒ… ์„œ๋ฒ„ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
Thread Server has a very basic chat server structure.

๐Ÿ‘‰๐Ÿป Echo Server

โœ”๏ธ Server.cpp

#include <iostream>
#include <sys/socket.h> // ์†Œ์ผ“ API / Socket API
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>

int main() {

    // ์†Œ์ผ“ ์ƒ์„ฑ,0์€ ํ”„๋กœํ† ์ฝœ ์ž๋™ ์„ ํƒ
    // // Create socket, 0 for automatic protocol selection
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);

    sockaddr_in address;
    address.sin_family = AF_INET; // IPv4
    address.sin_addr.s_addr = INADDR_ANY; // ๋ชจ๋“  IP ํ—ˆ์šฉ / Allow all IPs
    address.sin_port = htons(5080); // ํฌํŠธ 8080 / Port 8080

    bind(server_fd, (struct sockaddr*)&address, sizeof(address)); // ์ฃผ์†Œ ๋ฐ”์ธ๋”ฉ / Address Binding
    listen(server_fd, 3); // ์ ‘์† ๋Œ€๊ธฐ / Waiting for connection

    std::cout << "listening..." << std::endl;

    int new_socket = accept(server_fd, nullptr, nullptr); // ์—ฐ๊ฒฐ ์ˆ˜๋ฝ / Accept Connection

    char buffer[1024] = {0};
    read(new_socket, buffer, 1024); // ๋ฐ์ดํ„ฐ ์ˆ˜์‹  / Receive Data
    std::cout << "์ˆ˜์‹ ๋œ ๋ฉ”์‹œ์ง€ / Received Message: " << buffer << std::endl;

    const char* hello = "Hello from server";
    send(new_socket, hello, strlen(hello), 0); // ์‘๋‹ต ์ „์†ก / Send Response

    close(new_socket);
    close(server_fd);
    return 0;
}

โœ”๏ธ Client.cpp

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0); // ์†Œ์ผ“ ์ƒ์„ฑ / create socket

    sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5080);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr); // ์„œ๋ฒ„ IP ์„ค์ • / Server IP settings

    connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); // ์„œ๋ฒ„ ์ ‘์† / server connection

    const char* message = "Hello from client";
    send(sock, message, strlen(message), 0); // ๋ฉ”์„ธ์ง€ ์ „์†ก / Send Message

    char buffer[1024] = {0};
    read(sock, buffer, 1024); // ์„œ๋ฒ„ ์‘๋‹ต ์ˆ˜์‹  / Receive Server Response
    std::cout << "์„œ๋ฒ„ ์‘๋‹ต / Server Response: " << buffer << std::endl;

    close(sock); // ์†Œ์ผ“ ์ข…๋ฃŒ / Close Socket
    return 0;
}

โœ”๏ธ ์ปดํŒŒ์ผ / Compiling

g++ Server.cpp -o server -std=c++17
g++ Client.cpp -o client -std=c++17

โœ”๏ธ ์‹คํ–‰ / Run

./server
./client

โœ”๏ธ ๊ฒฐ๊ณผ / Result

# server
MacBookAir echo % ./server
listening...
์ˆ˜์‹ ๋œ ๋ฉ”์‹œ์ง€ / Received Message: Hello from client

# client
MacBookAir echo % ./client
์„œ๋ฒ„ ์‘๋‹ต / Server Response: Hello from server

๐Ÿ‘‰๐Ÿป ThreadServer

โœ”๏ธthreadServer.cpp

#include <iostream>
#include <thread> // ์Šค๋ ˆ๋“œ ํ—ค๋” / thread header
#include <vector>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>

// ํด๋ผ์ด์–ธํŠธ์™€ ํ†ต์‹ ํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜
// A function to communicate with the client
void handle_client(int client_socket) {
    char buffer[1024];
    while (true) {

        // ๋ฒ„ํผ๋ฅผ ๋ชจ๋‘ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ด์„œ ๊ธฐ์กด ์“ฐ๋ ˆ๊ธฐ ๊ฐ’ ์ง€์šฐ๊ธฐ
        // Initialize buffer to all 0s to clear existing garbage values
        memset(buffer, 0, 1024);
        ssize_t valread = read(client_socket, buffer, 1024);

        if (valread <= 0) {
            std::cout << "ํด๋ผ์ด์–ธํŠธ ์ ‘์† ์ข…๋ฃŒ / Client connection terminated " << std::endl;
            break;
        }

        std::cout << "์ˆ˜์‹ ๋œ ๋ฉ”์‹œ์ง€ / Received message: " << buffer << std::endl;
        send(client_socket, buffer, valread, 0); // send
    }
    close(client_socket);
}

int main() {
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);

    // ํฌํŠธ๊ฐ€ ์ด๋ฏธ ์‚ฌ์šฉ ์ค‘์ด์–ด๋„ ์ฆ‰์‹œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์„ค์ •
    // Configure port to be immediately reusable even if it is already in use
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(5080);

    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
        perror("Bind failed"); // ์—๋Ÿฌ ๋‚ด์šฉ ์ถœ๋ ฅ / Error details output
        return 1;
    }

    if (listen(server_fd, 5) < 0) {
        perror("Listen failed");
        return 1;
    }

    std::cout << "์„œ๋ฒ„ ์ •์ƒ ์‹œ์ž‘, ์ ‘์† ๋Œ€๊ธฐ ์ค‘ / Server started normally, waiting for connection ..." << std::endl;

    while (true) {
        int client_sock = accept(server_fd, nullptr, nullptr);
        if (client_sock < 0) {
            perror("Accept failed");
            continue;
        }
        std::cout << "์ƒˆ ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ๋จ / New Client Connected: " << client_sock << ")" << std::endl;
        std::thread(handle_client, client_sock).detach();
    }
    return 0;
}

โœ”๏ธClient.cpp

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0); // ์†Œ์ผ“ ์ƒ์„ฑ / create socket

    sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5080);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr); // ์„œ๋ฒ„ IP ์„ค์ • / Set Server IP

    connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); // ์„œ๋ฒ„ ์ ‘์† / Connect to Server

    // const char* message = "Hello from client";
    // send(sock, message, strlen(message), 0); // ๋ฉ”์‹œ์ง€ ์ „์†ก

    // char buffer[1024] = {0};
    // read(sock, buffer, 1024); // ์„œ๋ฒ„ ์‘๋‹ต ์ˆ˜์‹ 
    // std::cout << "์„œ๋ฒ„ ์‘๋‹ต: " << buffer << std::endl;


    while (true) {
        std::string msg;
        std::cout << "๋ณด๋‚ผ ๋ฉ”์‹œ์ง€ (์ข…๋ฃŒ๋Š” quit): ";
        std::getline(std::cin, msg); // ํ‚ค๋ณด๋“œ ์ž…๋ ฅ ๋ฐ›๊ธฐ / Receiving keyboard input

        // quit๊ฐ€ ์ž…๋ ฅ๋˜๋ฉด... / When quit is entered...
        if (msg == "quit") break;

        send(sock, msg.c_str(), msg.length(), 0); // ๋ฉ”์„ธ์ง€๋ฅผ ์„œ๋ฒ„๋กœ ์ „์†ก / Send message to server

        char buffer[1024] = {0};
        int valread = read(sock, buffer, 1024); // ์„œ๋ฒ„ ์‘๋‹ต ๋Œ€๊ธฐ / Waiting for server response

        if (valread <= 0) {
            std::cout << "์„œ๋ฒ„์™€์˜ ์—ฐ๊ฒฐ์ด ๋Š๊ฒผ์Šต๋‹ˆ๋‹ค. / Server connection closed." << std::endl;
            break;
        }
        std::cout << "์„œ๋ฒ„ ์‘๋‹ต / Server response:: " << buffer << std::endl;
    }



    close(sock); // ์†Œ์ผ“ ์ข…๋ฃŒ / Socket close
    return 0;
}

โœ”๏ธ ์ปดํŒŒ์ผ / Compiling

g++ threadServer.cpp -o server -std=c++17 -pthread
g++ Client.cpp -o client -std=c++17

โœ”๏ธ ์‹คํ–‰ / Run

./server
./clinet

โœ”๏ธ๊ฒฐ๊ณผ / Result

# server
MacBookAir thread % ./server
์„œ๋ฒ„ ์ •์ƒ ์‹œ์ž‘, ์ ‘์† ๋Œ€๊ธฐ ์ค‘ / Server started normally, waiting for connection ...
์ƒˆ ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ๋จ / New Client Connected: 4)
์ˆ˜์‹ ๋œ ๋ฉ”์‹œ์ง€ / Received message: hello
์ˆ˜์‹ ๋œ ๋ฉ”์‹œ์ง€ / Received message: ์•ˆ๋…•ํ•˜์„ธ์š”
์ˆ˜์‹ ๋œ ๋ฉ”์‹œ์ง€ / Received message: 8
ํด๋ผ์ด์–ธํŠธ ์ ‘์† ์ข…๋ฃŒ / Client connection terminated 

#client
MacBookAir thread % ./client
๋ณด๋‚ผ ๋ฉ”์‹œ์ง€ / Message to send (์ข…๋ฃŒ/Quit: quit): hello
์„œ๋ฒ„ ์‘๋‹ต / Server response:: hello
๋ณด๋‚ผ ๋ฉ”์‹œ์ง€ / Message to send (์ข…๋ฃŒ/Quit: quit): ์•ˆ๋…•ํ•˜์„ธ์š”
์„œ๋ฒ„ ์‘๋‹ต / Server response:: ์•ˆ๋…•ํ•˜์„ธ์š”
๋ณด๋‚ผ ๋ฉ”์‹œ์ง€ / Message to send (์ข…๋ฃŒ/Quit: quit): 8
์„œ๋ฒ„ ์‘๋‹ต / Server response:: 8
๋ณด๋‚ผ ๋ฉ”์‹œ์ง€ / Message to send (์ข…๋ฃŒ/Quit: quit):  quit
MacBookAir thread % 

Leave a Reply