[Webserver]httplib webserver+Websocket

๐Ÿ‘‰๐Ÿป ์•„๋ž˜๋Š” ์›น์†Œ์ผ“์— ๋Œ€ํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค.
Below is an explanation of WebSockets.

๐Ÿ‘‰๐Ÿป ์›น์†Œ์ผ“์€ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ„์˜ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
WebSockets enable bidirectional communication between a server and a client.

๐Ÿ‘‰๐Ÿป ์•„๋ž˜์˜ ์ฝ”๋“œ๋Š” ์›น์†Œ์ผ“์„ ์‚ฌ์šฉํ•ด์„œ ๊ฐ„๋‹จํ•œ ์ฑ„ํŒ…๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
The code below implements a simple chat function using WebSockets.

๐Ÿ‘‰๐Ÿป ํ„ฐ๋ฏธ๋„๊ณผ ๋ธŒ๋ผ์šฐ์ €๊ฐ„์˜ ์ฑ„ํŒ…์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
Chatting between the terminal and the browser is possible.

๐Ÿ‘‰๐Ÿป bc_server.cpp

โœ”๏ธ์„œ๋ฒ„์™€ ๋ธŒ๋ผ์šฐ์ € ํด๋ผ์ด์–ธํŠธ์— ๋Œ€ํ•œ ์„ค์ •์ด ์žˆ์Šต๋‹ˆ๋‹ค.
There are settings for the server and the browser client.

โœ”๏ธ ์ฝ”๋“œ / Code

#include "httplib.h"
#include <algorithm>
#include <iostream>
#include <mutex>
#include <string>
#include <vector>

/* ---- ๋ชจ๋“  ์†Œ์ผ“ ์ ‘์†์ž์—๊ฒŒ ๋ฉ”์„ธ์ง€ ์ „์†ก / Send message to all socket connected users---- */
std::mutex g_mtx;

// g_clients ๋ชจ๋“  ์›น์†Œ์ผ“ ํด๋ผ์ด์–ธํŠธ / g_clients all WebSocket clients
std::vector<httplib::ws::WebSocket*> g_clients;

void broadcast(const std::string& msg) {

    // ์Šค๋ ˆ๋“œ์—์„œ ๊ฐ™์€๋ฐ์ดํ„ฐ ๊ฑด๋“œ๋ฆด๋•Œ ์ถฉ๋Œ๋ง‰๋Š” ์•ˆ์ „์žฅ์น˜
    // A safety mechanism to prevent conflicts when threads access the same data
    std::lock_guard<std::mutex> lock(g_mtx);
    // ๋ชจ๋“  ์†Œ์ผ“ ์ ‘์†์ž์—๊ฒŒ ๋ฉ”์„ธ์ง€์ „๋‹ฌ / Deliver message to all socket users
    for (auto* c : g_clients) {
        c->send(msg);
    }
}

int main() {
    httplib::Server svr;

    svr.Get("/", [](const httplib::Request&, httplib::Response& res) {
        res.set_content(R"(
        <!doctype html><html><body>
        <input id="msg" value="hello aloy~~๐Ÿ‘‹"><button id="send">Send</button>
        <pre id="log"></pre>
        <script>
        const log = document.getElementById('log');
        const ws = new WebSocket('ws://localhost:5080/ws');
        ws.onmessage = (e) => log.textContent += '[recv] ' + e.data + '\n';
        document.getElementById('send').onclick = () => {
        const v = document.getElementById('msg').value;
        const vplus = "๐Ÿ‘‰๐Ÿป" +  v;

        //ws.send(v);
        ws.send(vplus);
        log.textContent += '[send] ' + v + '\n';
        };
        </script></body></html>
        )", "text/html; charset=utf-8");
    });

    svr.WebSocket("/ws", [](const httplib::Request&, httplib::ws::WebSocket& ws) {
        {
            std::lock_guard<std::mutex> lock(g_mtx);
            g_clients.push_back(&ws);
        }

        std::string msg;
        while (ws.read(msg)) {
            broadcast(msg); // ๋ชจ๋‘์—๊ฒŒ ์ „์†ก / send to everyone
        }

        {
            std::lock_guard<std::mutex> lock(g_mtx);
            g_clients.erase(std::remove(g_clients.begin(), g_clients.end(), &ws), g_clients.end());
        }
    });

    std::cout << "ws server: http://localhost:5080\n";
    svr.listen("0.0.0.0", 5080);
}

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

g++ bc_server.cpp -o bc_server -std=c++17 -pthread

โœ”๏ธ ์„œ๋ฒ„์‹คํ–‰ / Run Server

Run Server

๐Ÿ‘‰๐Ÿป client.cpp

โœ”๏ธ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰๊ฐ€๋Šฅํ•œ ํด๋ผ์ด์–ธํŠธ์ž…๋‹ˆ๋‹ค.
This is a client executable in the terminal.

โœ”๏ธ ์ฝ”๋“œ / Code

#include "httplib.h"
#include <atomic>
#include <iostream>
#include <string>
#include <thread>

int main() {
    httplib::ws::WebSocketClient ws("ws://localhost:5080/ws");
    if (!ws.connect()) {
        std::cerr << "connect failed\n";
        return 1;
    }

    std::atomic<bool> running{true};

    // ์ˆ˜์‹  ์Šค๋ ˆ๋“œ / receive thread
    std::thread reader([&]() {
        std::string msg;
        while (running && ws.read(msg)) {
            std::cout << "[recv] " << msg << '\n';
        }
        running = false;
    });

    std::cout << "connected. type message and press Enter.\n";
    std::cout << "type /quit to exit.\n";

    // ์†ก์‹  ๋ฃจํ”„ / Send loop
    std::string line;
    while (running && std::getline(std::cin, line)) {
        if (line == "/quit") break;
        // ws.send(line);
        ws.send("โญ๏ธ" + line);
    }

    running = false;
    ws.close();
    if (reader.joinable()) reader.join();

    std::cout << "closed\n";
    return 0;
}

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

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

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

Leave a Reply