Boost๋ C++์ ํ๋ค๋ณด๋ฉด ์ธ์ ๊ฐ ๋ฐ๋์ ๊ผญ ์ฌ์ฉํ๊ฒ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค
Boost์ ๋ํ ์ค๋ช ์ ์๋์ ์ฒจ๋ถํ Boost ๊ณต์ํํ์ด์ง์์ ํ๋ฒ ์ฝ์ด๋ณด๋๊ฑธ ์ถ์ฒํ๋ค (์ฌ๋ฐ์)
์ฒ์์ boost๋ฅผ ์ฌ์ฉํ ๋๋,
STL(Standard Template Library)์ด๋ ์ญํ ์ด ๊ฐ์ ๊ฒ ๊ฐ์๋ฐ, ์ ์ฐ์ง? ํ๋๋ฐ
STL์ ํ์ฉํด์ ๋ญ๊ฐ ์ข๋ ํด์ผํ ๋, boost์๋ ์ด๋ฏธ ์๋ ๊ธฐ๋ฅ์ด ๋ง์ด ์์๋ค
์์ ํ์ฉํด์ ์ฐ๋ค๋ณด๋ฉด ๊ธ๋ฐฉ ์ต์ํด์ง ์ ์๋น
์๋ก ์ด ๊ธธ์๋๋ฐ,
Boost ํ์ฉ์ ์ข ๋ ์ํด๋ณด๊ธฐ ์ํด์, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ํ ์ฝ๋๋ฅผ ํ๋ฒ์ฉ
๊ณต๋ถํด๋ณด๋ ค๊ณ ํ๋ค
์ค์ ํ์ฉํ ๋ ๋์น ๋ถ๋ถ ํ์ธ๋ ํ ๊ฒธใ
Boost Asio์ ๋ํ ์ค๋ช ์ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ๊ธธ ๋ฐ๋๋ค
์ฒซ ๋ฒ์งธ๋ก ํ์ธํ ์์ ๋ Async TCP Server์ Client ๊ตฌํ ์์ ์ด๋ค
boost ์ฝ๋๋ ์ฒจ๋ถ ๋งํฌ์๋ ๋ฌ์ ๋์์ผ๋ ์ฐธ๊ณ ํ์๊ธธ...
์ํ์ฝ๋์ ๋์์ ํ์ธํ ๋ก๊ทธ๋ง ๋ช ์ค ์ถ๊ฐํด์ ํ์ธํ๊ฑด ๊นํ์ ์ฌ๋ ค๋์๋น..
(github.com/bell-2/practice_01_boost)
๋ด๊ฐ ์ดํดํ๋๋ฐ ์๊ฐ ๊ฑธ๋ฆฐ ๋ถ๋ถ๋ง ์ ๋ฆฌํ๋๊ฑธ๋ก
1. ์ด๋ค Boost ์์ ๋ฅผ ๋ณผ๊น
- Async TCP Server (/boost_asio/example/echo/async_tcp_echo_server.cpp)
- Async TCP Client(/boost_asio/example/timeouts/async_tcp_client.cpp)
Timouts ํ์์ ์๋ ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ ค ํ๋๋ฐ,
Server์ฉ ์ฝ๋๋ echo์ ํฌํจ๋์ด์๋๊ฒ ๋ ๋ณด๊ธฐ ํธํด์,
์๋ ๊ฒ ๋ ๊ฐ๋ฅผ ์์๋ดค๋ค
sync๋ async ์ดํดํ๋ฉด ์ฝ๊ฒ ์ดํด๊ฐ
2. Async TCP Server
(1) Asio Service ๊ฐ์ฒด ์์ฑ
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: async_tcp_echo_server <port>\n";
return 1;
}
boost::asio::io_service io_service;
server s(io_service, atoi(argv[1]));
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
main ํจ์๋ฅผ ๋จผ์ ๋ณด๋ฉด,
Boost Asio๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ io_service ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ
server๋ผ๋ ํด๋์ค์ ํด๋น ๊ฐ์ฒด๋ฅผ ๋ฃ์ด ์์ฑ์๋ฅผ ํธ์ถํ๊ณ ์๋ค
server ํด๋์ค์์ io_service์ ๋ญ๊ฐ๋ฅผ ์ ํ ํด์ฃผ๋ ค๊ณ ๋ฃ๋๊ฑธํ ๊ณ ,
๊ทธ๋ ๊ฒ ์ค์ ๋ io_service์ ๋ํด์ run()์ ํด์ฃผ๊ณ ์๋ค
io_service ์์ → run()
io_service ์ข ๋ฃ → stop()
๊ทธ๋ผ server ํด๋์ค์์ io_service์๊ฒ ๋ญ ํ๋์ง ๋ณด๋๋ก ํ์
(2) Accept ํ๋ server Class
class server
{
public:
server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
session* new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
/* .... */
private:
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
server ํด๋์ฐ์ ์์ฑ์๋ถํฐ ๋ณด๋ฉด,
io_service ๊ฐ์ฒด๋ฅผ ๋ฐ์์ค๊ณ , ์๋ฒ๊ฐ ์ด์ด๋ port ์ ๋ณด๋
tcp::acceptor ๋ก ์ฃผ๊ณ ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค (io_service๋)
ip::tcp:acceptor
์๋ ์ด๋ฆ์ typedef basic_socket_acceptor <tcp> acceptor;์ด๋ค
(socket ํต์ ์์ ์ฌ์ฉํ๋ ๊ทธ acceptor ๋ง์ต๋๋ค)
ํด๋ผ์ด์ธํธ๊ฐ ์ ์ํ Port๋ฅผ ์ด์ด๋๊ณ ์ฐ๊ฒฐ์ ๋ํด acceptํ ์ค๋น๋ฅผ ํ๋ค
boost ๊ณตํ์ type๊ณผ member functions๋ค์ด ์ ์ ๋์ด์์ผ๋ ์ฐธ๊ณ ํ๋ค
basic_socket_acceptor::async_accept
๋น๋๊ธฐ ํต์ ์ accept๋ผ ์ด๋ฆ์ด async_accept๋ค
๋ง ๊ทธ๋๋ก async accept๋ฅผ ์์ํ๋ ์ญํ ์ด๋ค
ํจ์ ๋ชจ์์ ๋ค์๊ณผ ๊ฐ๋ค
template< typename MoveAcceptHandler>
DEDUCED async_accept(
boost::asio::io_context & io_context, MoveAcceptHandler && handler);
์ฃผ๋ชฉํด์ผํ ๊ฑด ๋ ๋ฒ์งธ ์ธ์์ธ handler์ด๋ค
boost๋ asio ํต์ ์ ์ฑ๊ณต/์คํจ์ ๊ฒฐ๊ณผ๋ฅผ callback ํํ๋ก ๋๋ ค์ค๋ค
๊ทธ๋์ accept_async()๋ฅผ ์ํํ๊ฑฐ์๋ asio๋ก๋ถํฐ ๊ฒฐ๊ณผ๋ฅผ ์์ ํ
ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋ก์ ํด์ฃผ๋๊ฑฐ๋ค
์์ ์์ ์์๋ boost::bind()๋ฅผ ์ฌ์ฉํด์ ๋ฑ๋กํ ํธ๋ค๋ฌ์
ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ด ๋๊ฒจ์ฃผ๊ณ ์๋ค
๊ทธ๋ฌ๋ฉด callback ํจ์๋ก ๋ฑ๋กํด์ฃผ๊ณ ์๋ server::handle_accept๋ฅผ ๋ด๋ณด์
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
cout << "START SESSION..." << endl;
new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
else
{
delete new_session;
}
}
asio์์ accept๋ฅผ ํ๊ณ ๋๋ฉด ์ฐ๋ฆฌ๊ฐ ๋ฑ๋กํ ์ด ํจ์๊ฐ ์คํ์ด ๋๋ค
์ฑ๊ณต/์คํจ์ ๋ํ ๊ฒฐ๊ณผ๋ boost::system::error_code ํํ๋ก ๋ฐ๊ฒ ๋๋ค
boost::system::error_code
error code์ ๋ฆฌ์คํธ๋ enum ์ผ๋ก ์ ์๋์ด ์๋ค
๊ฐ์ด ๋ญ์ง ์ป์ด์ค๊ณ ์ถ๋ค๋ฉด ์๋ ๋๊ฐ api๋ก ๊ฐ์ ธ์ฌ ์ ์๋ค
error.value() → ์ซ์ ํํ์ Error code
error.message() → ๋ฌธ์์ด๋ก ๋ฐ์ ์ ์์
๋ค์ ์ฝ๋๋ก ๋์๊ฐ์,
์์ ์์๋ session ํด๋์ฐ์ ๊ฐ์ฒด๋ฅผ ๋ฐ๊ณ ,
์ฌ๋ฌ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์ฐ๊ฒฐ ์์ฒญ์ด ์ฌ ๊ฒ์ ์ํด
์๋ก์ด accept๋ฅผ ์์ฑํด์ฃผ๋ ๊ฑธ ๋ณผ ์ ์๋ค
(3) session ์์ฑ
๊ทธ๋ฌ๋ฉด ์๋ฒ์์ ํด๋ผ์ด์ธํธ์์ ์ธ์ ์ด ์์ฑ๋๊ณ
์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฝ๊ณ ๊ทธ์ ๋ํด ์๋ตํ๋
session ํด๋์ค๋ฅผ ๋ณด๋๋ก ํ๊ฒ ๋ค
session* new_session = new session(io_service_);
async_accept์์๋ ํ๋ผ๋ฏธํฐ๋ก ๋ฃ์ด์ฃผ๊ณ ์๋ new_session ๊ฐ์ฒด
class session
{
public:
session(boost::asio::io_service& io_service)
: socket_(io_service)
{
cout << "NEW SESSION..." << endl;
}
/*....*/
private:
tcp::socket socket_;
};
session ํด๋์ค์ ์์ฑ์์์๋ io_service ๊ฐ์ฒด๋ฅผ ๋ฐ์์
tcp::socket๋ฅผ ์ด๊ธฐํ ํด์ฃผ๊ณ ์๋ค
ip::tcp::socket
์๋ ์ด๋ฆ์ typedef basic_stream_socket< tcp >์ด๋ค
stream-oriented socket ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค๊ณ ํ๋ค
๋ง์ด ์ด๋ ต์ง๋ง, socket ํต์ ์ ๊ฐ๋ฅํ๋๋ก ํด์ฃผ๋ ๋ณ์์ผ๋ฟ...!
fd๋ฅผ ํตํด์ ํ๋ ๊ฒ์ฒ๋ผ...!
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
/*...*/
new_session->start();
/*...*/
}
handle_accept์์ session ํด๋์ค ๊ฐ์ฒด์ ๋ํด start()๋ผ๋
ํจ์๋ฅผ ํธ์ถํ๋๊ฒ ๋ณด์์๊ฑฐ๋ค
void start()
{
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
์๋ ๋ญํ๋ ํจ์๋๋ฉด, ์๊น ์์์ accept๋ฅผ ํ๊ณ ์ถ์ผ๋ฉด
accept ๊ฒฐ๊ณผ๋ฅผ ์์ ํ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๋ผ๊ณ ํ์๋ค
๋ง์ฐฌ๊ฐ์ง๋ก,
์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฝ๊ธฐ ์ํด read๋ฅผ ํ๊ณ ์ถ์ผ๋ฉด
read์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ ํธ๋ค๋ฌ(session::handle_read)๋ฅผ
๋ฑ๋กํด์ ์ฌ์ฉํ๋๊ฑฐ๋ค
boost::asio::async_read_some
๋น๋๊ธฐ์ read๋ฅผ ์์ํ๋๋ก ํ๋ ์ญํ ์ ํ๋ค
์ฐพ์๋ณด๋ฉด, readํ๋ ํจ์๋ async_read(), async_read_untill() ๋ฑ๋ฑ
์ฌ๋ฌ๊ฐ์ง๊ฐ ์์์
async_read_some ์ํ์ ๋ค์๊ณผ ๊ฐ๋ค
template<
typename MutableBufferSequence,
typename ReadHandler>
void async_read_some(
const MutableBufferSequence & buffers,
ReadHandler handler);
๋ญ์ผ ๋ญ๋ฐ? ํ ์ ์์ ,ใด
๋จ์ํ (์ฝ์๊ฑฐ ์ ์ฅํ buffer, ๋ฑ๋กํ ํธ๋ค๋ฌ) ์ด๊ฑฐ๋ค
boost::asio::buffer
์ฝ์ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ์ ์๋ ๋ฒํผ์ด๋ค
ํ์ํ๋ฉด ๋ณต์ฌํ ์๋ ์๋๋ฐ, ๋ฉ๋ชจ๋ฆฌ ์์ ๊ถ์ ํธ์ถ์์ ์๋ค๊ณ ํ๋
์ ํจํ ๋ฒํผ์ธ์ง ์ ๋ณด๋๋ก ํ์
bytes_transferred
size_t ๋ก ์ ์๋์ด ์๊ณ , asio๊ฐ readํ byte ์๋ฅผ
ํธ๋ค๋ฌ๋ฅผ ํตํด ๊ฐ์ด ์๋ ค์ค๋ค
(4) ํด๋ผ์ด์ธํธ ์์ฒญ์ ์ฝ์
๊ทธ๋ฌ๋ฉด async_read_some์ ํธ๋ค๋ฌ๋ก ๋ฑ๋กํ
readํ ๊ฒฐ๊ณผ๋ฅผ ๋๋ ค ๋ฐ์ ์ ์๋ handle_read()๋ฅผ ๋ณด๋๋ก ํ์
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
cout << "RECV MSG:\n" << data_ << endl;
boost::asio::async_write(socket_,
boost::asio::buffer(data_, bytes_transferred),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
delete this;
}
}
๋๋ ์์ ๋ณด๋ฉด์ ํท๊ฐ๋ ธ๋๊ฒ
์๋ ์ read๋ฅผ handleํ๋ ํจ์์ธ๋ฐ
์ฌ๊ธฐ์ write๋ฅผ ํ๋ ๊ฒ ๊ฐ์ ํจ์๊ฐ ์๋๊ฑฐ์ง...?? ์๋ค
๊ทผ๋ฐ ์ดํด๋ฅผ ํ๊ณ ๋๋๊น... ๋ค ์ฝ์์ผ๋ฉด
์๋ฒ๋๊น ํด๋ผ์ด์ธํธ์๊ฒ ์๋ต ํด์ค์ผ ๋น์ฐํ๊ฑฐ์๋ค
์ฌ๊ธฐ์๋ ๋จ์ํ error ์ฒดํฌ๋ง ํด์ฃผ๊ณ ,
์๋ต์ ๋ณด๋ผ async_write() ํจ์๋ฅผ ํธ์ถํด์ฃผ๊ณ ์๋ด
๊ทผ๋ฐ ํด๋น ์์ ๋ ํด๋ผ์ด์ธํธ์๊ฒ ๋ฐ์ ๋ฉ์์ง๋ฅผ
echo ํํ๋ก ์๋ฒ๊ฐ ๊ทธ๋๋ก ๋ค์ ๋๋ ค์ฃผ๋ ์์ ๋ผ์
bytes_transferred์ ๋ฐ์ buffer์ data๋ฅผ ๊ทธ๋๋ก ๋ค์ ๋ณด๋ด์ฃผ๊ณ ์์ผ๋๊น
์ค์ ์ฌ์ฉ ์์๋ ๋ค๋ฅธ ๋ณ์๋ฅผ ์จ์ ํด์ผํ๋ค
boost::asio::async_write
async_read()์ ๋น์ทํ๊ฒ ์๋ write ๊ธฐ๋ฅ์ ์ํํ ์ ์๋
ํจ์๋ฅผ ์ฌ๋ฌ๊ฐ ์ ๊ณตํ๋ค
(async_write_at, async_write_some ๋ฑ)
์๋ ๋์ผํ๊ฒ
boost :: asio :: async_write (์์ผ, boost :: asio :: buffer (๋ฐ์ดํฐ, ํฌ๊ธฐ), ํธ๋ค๋ฌ);
์ด๋ ๊ฒ ์จ์ฃผ๋ฉด ๋๊ฒ ๋ค
(5) ํด๋ผ์ด์ธํธ์๊ฒ ์๋ต์ ๋ณด๋ด์
๋ง์ง๋ง์ผ๋ก ์๋ต ๋ณด๋ด๋ ์ฝ๋๋ฅผ ๋ณด๊ฒ ๋ค
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
delete this;
}
}
์๋ฆ๋๊ฒ ๋ค๋ฅธ ํจ์๋๋ ๋น์ทํ๊ฒ
error ์ฒดํฌ ํ๊ณ , ์ ์๋ต์ ๋ณด๋๋ค๋ฉด ๊ทธ ๋ค์ ๋ญํ ์ง๋ฅผ ์์ฑํ์๋ค
์ด ์์ ๋ ์์ฝ ์๋ฒ๋ผ ๊ณ์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ณ ๋ฐ๊ณ ํ๋๊ฑฐ๋ผ
๋ค์ read๋ฅผ ํ๋ฌ ๊ฐ๊ณ ์์ง๋ง
์ผ๋ฐ์ ์ธ ์๋ฒ๋ฅผ ๊ตฌํํ๋ค๋ฉด, ์ฐ๊ฒฐ์ ๋๊ณ ์ธ์ ์ ๋ฆฌ๋ฅผ ํ๋ค๊ฑฐ๋
๊ทธ๋ฌ๋ฉด ๋ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค
ํด๋ผ์ด์ธํธ๋ ์ธ์ ์ ๋ฆฌํ ๊น? ์กฐ๊ธ ๊ท์ฐฎ์์ง๋ค...
๊ทผ๋ฐ ์ด๋ฏธ ์ธ์ ์ ๋ฆฌํ๋ค๊ฐ ์ฝ์ด ๋ช์ญ๊ฐ ๋ด๊ณ ์๋๋
์ ๋ฆฌํ๋๊ฒ ์๋ฏธ๊ฐ ์๋ค๋ ์๊ฐ์ด ๋ ๋ค ^^
์ ์ด๊ฒ ์ด๋์ ์ด๊ฑฐ์๊ตฌ๋...๋ฅผ ์ ์ ์์๋ค
์ ๋ฟ.๋ฏ.ํ.๋ค
ํน์ ์๋ชป๋ ๋ถ๋ถ์ด ์๋ค๊ฑฐ๋ ๊ทธ๋ฌ๋ฉด ์๋ ค์ฃผ์ญ์ผ
๐์ฐธ๊ณ ์๋ฃ๐
www.boost.org/
www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/example/timeouts/async_tcp_client.cpp
www.boost.org/doc/libs/1_52_0/doc/html/boost_asio/example/echo/async_tcp_echo_server.cpp
www.boost.org/doc/libs/1_76_0/doc/html/boost_asio.html
'๐ C๋ C++' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
C++ ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์์๋ณด์ - (2) shared_ptr (0) | 2021.06.25 |
---|---|
Error ํด๊ฒฐ: undefined reference to `vtable for XXX' (0) | 2021.06.24 |
C++ ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์์๋ณด์ - (1) unique_ptr (0) | 2021.05.25 |
Boost Asio์ ๋ํด์ ์์๋ณด์ (4) | 2021.05.20 |
C++ ํด๋์ค ๋ฉค๋ฒ๋ณ์ ์ด๊ธฐํ๋ฅผ ์์๋ณด์ (4) | 2021.03.25 |