ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ๐Ÿ”ง Boost.Asio ํŒจํ‚ท ์ˆ˜์‹  ์ตœ์ ํ™”: ์‹œ์Šคํ…œ ์ฝœ ์ตœ์†Œํ™” ๊ตฌํ˜„
    ์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ 2025. 5. 22. 07:41

     

    ๐Ÿ“Œ ๋ฐฐ๊ฒฝ ์„ค๋ช…

    MMORPG ๋˜๋Š” ์‹ค์‹œ๊ฐ„ ๊ฒŒ์ž„ ์„œ๋ฒ„์—์„œ๋Š” ์ˆ˜๋งŽ์€ ๋„คํŠธ์›Œํฌ ํŒจํ‚ท์„ ์ˆ˜์‹ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ๋ฐฉ์‹์œผ๋กœ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ํ—ค๋” → ๋ฐ”๋”” ์ˆœ์„œ๋กœ ์ฝ์œผ๋ฉฐ, ๊ฐ๊ฐ์˜ async_read()๋Š” ์‹œ์Šคํ…œ ์ฝœ์„ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

    async_read(socket, buffer(header_buf), ...);  // ์‹œ์Šคํ…œ ์ฝœ 1
    async_read(socket, buffer(body_buf), ...);    // ์‹œ์Šคํ…œ ์ฝœ 2
    

    ์ด ๋ฐฉ์‹์€ ๋‚ฎ์€ ์ฒ˜๋ฆฌ ํšจ์œจ, ๋†’์€ CPU ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


    โœ… ์ตœ์ ํ™” ์ „๋žต

    • ์‹œ์Šคํ…œ ์ฝœ 1ํšŒ: socket.async_read_some()์œผ๋กœ ํ•œ๊บผ๋ฒˆ์— ์ˆ˜์‹ 
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์—์„œ ํŒŒ์‹ฑ: ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒ„ํผ์— ์ €์žฅํ•˜๊ณ , ๋‚ด๋ถ€์—์„œ ํ—ค๋”/๋ฐ”๋”” ๊ตฌ๋ถ„
    • ๋ฒ„ํผ ๊ตฌ์กฐ: boost::asio::streambuf ๋˜๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ring buffer ์‚ฌ์šฉ

    ๐Ÿ“˜ ํ”„๋กœํ† ์ฝœ ๊ฐ€์ •

    • ๊ณ ์ •๋œ 2๋ฐ”์ดํŠธ ํ—ค๋” (๋ฐ”๋”” ๊ธธ์ด ์ •๋ณด ํฌํ•จ)
    • [Header(2 bytes)][Body(N bytes)]

    โœ… ์ตœ์ ํ™” ์˜ˆ์ œ ์ฝ”๋“œ

    #include <boost/asio.hpp>
    #include <iostream>
    #include <vector>
    #include <deque>
    
    using boost::asio::ip::tcp;
    
    class PacketReceiver {
    public:
        PacketReceiver(boost::asio::io_context& io_context)
            : socket_(io_context), stream_buf_() {}
    
        tcp::socket& socket() { return socket_; }
    
        void start() {
            do_read();
        }
    
    private:
        static constexpr size_t HEADER_SIZE = 2;
    
        tcp::socket socket_;
        boost::asio::streambuf stream_buf_;
    
        void do_read() {
            socket_.async_read_some(stream_buf_.prepare(1024),
                [this](boost::system::error_code ec, std::size_t bytes_transferred) {
                    if (!ec) {
                        stream_buf_.commit(bytes_transferred);
                        process_packets();
                        do_read(); // ๊ณ„์† ์ˆ˜์‹ 
                    } else {
                        std::cerr << "Receive failed: " << ec.message() << "\n";
                    }
                });
        }
    
        void process_packets() {
            while (true) {
                if (stream_buf_.size() < HEADER_SIZE)
                    return; // ํ—ค๋” ๋ถ€์กฑ
    
                std::istream is(&stream_buf_);
                is.unsetf(std::ios::skipws); // binary-safe ์ฝ๊ธฐ
    
                std::istream::pos_type pos = is.tellg();
                uint16_t body_len;
                is.read(reinterpret_cast<char*>(&body_len), HEADER_SIZE);
    
                if (stream_buf_.size() < HEADER_SIZE + body_len) {
                    // ๋ฐ”๋””๊นŒ์ง€ ๋„์ฐฉ ์•ˆ ํ–ˆ์œผ๋ฉด ๋‹ค์‹œ ๋’ค๋กœ
                    is.seekg(pos);
                    return;
                }
    
                std::vector<char> body(body_len);
                is.read(body.data(), body_len);
    
                handle_packet(body);
            }
        }
    
        void handle_packet(const std::vector<char>& body) {
            // ์‹ค์ œ ํŒจํ‚ท ์ฒ˜๋ฆฌ ๋กœ์ง
            std::cout << "[Packet Received] Size = " << body.size() << "\n";
        }
    };
    

    ๐Ÿง  ํ•ต์‹ฌ ์š”์  ์ •๋ฆฌ

    ํ•ญ๋ชฉ ์„ค๋ช…

    ๐Ÿ“ฅ ๋‹จ์ผ ์‹œ์Šคํ…œ ์ฝœ async_read_some() 1ํšŒ๋กœ ์—ฌ๋Ÿฌ ํŒจํ‚ท ์ˆ˜์‹  ๊ฐ€๋Šฅ
    ๐Ÿง  ํ—ค๋”/๋ฐ”๋”” ๊ตฌ๋ถ„์€ ์ˆ˜์‹  ํ›„ ํŒŒ์‹ฑ ๋ฒ„ํผ์—์„œ ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜์—ฌ ์„ฑ๋Šฅ ํ–ฅ์ƒ
    ๐Ÿ’พ ๋ฒ„ํผ ๊ตฌ์กฐ ์œ ์—ฐ streambuf, ring buffer ๋“ฑ ๋‹ค์–‘ํ•˜๊ฒŒ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
    ๐Ÿš€ ํšจ์œจ์ ์ธ ํŒจํ‚ท ์ฒ˜๋ฆฌ ์žฆ์€ read() ํ˜ธ์ถœ ์—†์ด๋„ ๋Œ€์šฉ๋Ÿ‰ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

    ๐Ÿ“ˆ ์„ฑ๋Šฅ ์ด์ 

    ์ธก๋ฉด ๊ฐœ์„  ํšจ๊ณผ

    ๐Ÿ” ์‹œ์Šคํ…œ ์ฝœ ์•ฝ 50% ์ด์ƒ ๊ฐ์†Œ (ํ—ค๋”+๋ฐ”๋”” ๋ถ„๋ฆฌ ์ˆ˜์‹  ๋Œ€๋น„)
    ๐Ÿงฉ ์บ์‹œ ํšจ์œจ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ์—ฐ์†์„ฑ ํ™•๋ณด
    โš™๏ธ CPU ์‚ฌ์šฉ๋Ÿ‰ ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ๋ณ‘๋ชฉ ์ตœ์†Œํ™”
    ๐ŸŒ ๋Œ€๋Ÿ‰ ํด๋ผ์ด์–ธํŠธ ์ฒ˜๋ฆฌ MMORPG ์„œ๋ฒ„ ๋“ฑ ๊ณ ์„ฑ๋Šฅ ์š”๊ตฌ ์ƒํ™ฉ์— ์ ํ•ฉ

    โœ… ์ถ”๊ฐ€ ํŒ

    • boost::asio::mutable_buffer๋ฅผ ํ™œ์šฉํ•œ ์ปค์Šคํ…€ ๋ฒ„ํผ ๊ด€๋ฆฌ๋„ ๊ฐ€๋Šฅ
    • tcp::no_delay ์˜ต์…˜ ํ™œ์„ฑํ™”ํ•˜์—ฌ Nagle ๋น„ํ™œ์„ฑํ™”
    • ๋ง ๋ฒ„ํผ ๊ธฐ๋ฐ˜ ํŒจํ‚ท ์ˆ˜์‹ ๊ธฐ๋กœ ํ™•์žฅ ์‹œ ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ์ฒ˜๋ฆฌ์™€๋„ ๊ถํ•ฉ์ด ์ข‹์Œ

    ํ•„์š”ํ•˜์‹œ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ™•์žฅ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:

    • ์‚ฌ์šฉ์ž ์ •์˜ ๋ง ๋ฒ„ํผ ๊ตฌ์กฐ ๊ธฐ๋ฐ˜ ์ˆ˜์‹ ๊ธฐ ์˜ˆ์ œ
    • async_write()๋ฅผ ํ†ตํ•œ ํŒจํ‚ท ์ „์†ก ๊ตฌ์กฐ
    • ๊ณ ์ • ํ—ค๋”/๊ฐ€๋ณ€ ๋ฐ”๋”” ๊ตฌ์กฐ์˜ ์ถ”์ƒํ™” ํด๋ž˜์Šค ์„ค๊ณ„

     

Designed by Tistory.