[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