-
๐ง 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()๋ฅผ ํตํ ํจํท ์ ์ก ๊ตฌ์กฐ
- ๊ณ ์ ํค๋/๊ฐ๋ณ ๋ฐ๋ ๊ตฌ์กฐ์ ์ถ์ํ ํด๋์ค ์ค๊ณ