검색결과 리스트
Server에 해당되는 글 1건
글
Daytime.3 - An asynchronous TCP daytime server
다음에 기반함
http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/tutorial/tutdaytime3.html
main 함수
int main() { try {
먼저, 클라이언트의 연결요청을 받아들일 객체가 필요하다. io_service 객체는 소켓과 같은 I/O 서비스를 제공하므로, 이를 이용하자.
boost::asio::io_service io_service; tcp_server server(io_service);
io_service 객체를 run 하여 비동기 연산을 수행하도록 하자.
io_service.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return 0; }
tcp_server 클래스
class tcp_server { public:
생성자에서 포트 13의 요청을 listen 하도록 초기화 해주자.
tcp_server(boost::asio::io_service& io_service) : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13)) { start_accept(); } private:
start_accept() 함수에서 소켓을 생성하고 async accept 를 시작하여 새로운 연결을 받아들이자.
void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service()); acceptor_.async_accept(new_connection->socket(), boost::bind(&tcp_server::handle_accept, this, new_connection, boost::asio::placeholders::error)); }
handle_accept 는 start_accept 함수가 종료되어 accept 연산이 개시될 때 호출된다. 이 함수에서 클라이언트의 요청을 처리하고, start_accept() 를 다시 호출하여 다음 연결 요청을 받을 수 있도록 하자.
void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) { if (!error) { new_connection->start(); } start_accept(); }
tcp_connection 클래스
shared_ptr 과 enable_shared_from_this 를 활용하여 관련한 연산이 수행되는 한 tcp_connection 객체가 소멸되지 않도록 유지하자.
class tcp_connection : public boost::enable_shared_from_this<tcp_connection> { public: typedef boost::shared_ptr<tcp_connection> pointer; static pointer create(boost::asio::io_service& io_service) { return pointer(new tcp_connection(io_service)); } tcp::socket& socket() { return socket_; }
start() 함수에서는 boost::asio::async_write() 함수를 활용하여 클라이언트로 데이터를 전송한다.
ip::tcp::socket::async_write_some() 대신 async_write 를 사용하여 전체 데이터 블록이 전송될 수 있도록 했음을 확인하자.
void start() {
비동기로 메시지를 전송하는 것이 완료될 때까지 데이터가 유효함을 보장하기 위해 클래스 멤버로 데이터를 보관 할 것이다.
message_ = make_daytime_string();
boost::bind() 를 활용하여 비동기 연산을 수행할때, 핸들러의 parameters 와 호출부의 arguments 가 일치하도록 주의한다.
placeholder 들 (boost::asio::placeholders::error / boost::asio::placeholders::bytes_transferred) 이 handle_write() 에서 사용되지 않기때문에, 실수로 제거될 수 있다.
boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&tcp_connection::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
이 연결에 필요한 기타 추가 작업들은 이제 handle_write() 에서 모두 처리하면 된다.
} private: tcp_connection(boost::asio::io_service& io_service) : socket_(io_service) { } void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/) { } tcp::socket socket_; std::string message_; };
불필요한 핸들러 인자 제거
우리의 예제에서, error 와 bytes_transsferred 인자는 handle_write 함수 몸체에서 불필요하다. 이러한 경우, 함수에서 이를 제거하여 다음과 같은 시그니쳐를 갖게 할 수 있다.
void handle_write() { }
이 함수를 호출부인 boost::asio::async_write() 를 호출할때에는 다음과 같이 수정하면 된다.
boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&tcp_connection::handle_write, shared_from_this()));
정리
1. main 함수
* tcp_server 에 io_service 를 전달하여 생성하고, tcp_server 클래스를 initiate 한다.
* 메인 스레드에서 tcp_server 에서 사용하는 io_service 의 run() 함수 호출
2. tcp_server 클래스
* boost::asio::ip::tcp::begin_accept 를 활용하여 클라이언트의 연결을 받고, tcp_connection 객체를 생성한다.
* connection 의 start 함수를 호출한다.
* 완료 된 후, 다음 연결을 받기 위해 다시 accept 를 시작한다.
3. tcp_connection 클래스
* enable_shared_from_this 를 활용하여 이 객체에 대한 연산이 수행되는 경우 소멸되지 않도록 보장한다.
* 클라이언트로 전달하는 데이터가 소멸되지 않게 하기 위해, 클래스의 멤버로 데이터를 보전한다.
* 전송 데이터가 분리되지 않게 하기 위해 async_write() 함수를 활용
* 사용하지 않는 place_holder 를 제거하여 핸들러 인자의 시그니쳐를 단순히 가져 갈 수도 있다 (async_write)
Full source code
--
#pragma once #include#include #include #include "boost/shared_ptr.hpp" #include "boost/asio.hpp" #include "boost/bind.hpp" #include "boost/enable_shared_from_this.hpp" //* enable_shared_from_this 를 활용하여 이 객체에 대한 연산이 수행되는 경우 소멸되지 않도록 보장한다. //* 클라이언트로 전달하는 데이터가 소멸되지 않게 하기 위해, 클래스의 멤버로 데이터를 보전한다. //* 전송 데이터가 분리되지 않게 하기 위해 async_write() 함수를 활용 //* 사용하지 않는 place_holder 를 제거하여 핸들러 인자의 시그니쳐를 단순히 가져 갈 수도 있다(async_write) class TCPConnection : public boost::enable_shared_from_this { public: typedef boost::shared_ptr pointer; static pointer create(boost::asio::io_service& io) { return pointer(new TCPConnection(io)); } boost::asio::ip::tcp::socket& socket() { return socket_; } void start() { message_ = make_daytime_string(); boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&TCPConnection::handle_write, shared_from_this())); } private: TCPConnection(boost::asio::io_service& io) : socket_(io) { } void handle_write() { std::cout << message_ << ", write_done" << std::endl; } std::string make_daytime_string() { std::time_t now = time(0); return ctime(&now); } boost::asio::ip::tcp::socket socket_; std::string message_; }; //* boost::asio::ip::tcp::begin_accept 를 활용하여 클라이언트의 연결을 받고, tcp_connection 객체를 생성한다. //* connection 의 start() 함수를 호출한다. //* 완료 된 후, 다음 연결을 받기 위해 다시 accept 를 시작한다. class TCPServer { public: TCPServer(boost::asio::io_service& io) : acceptor_(io, boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4(), 13)) { start_accept(); } private: void start_accept() { TCPConnection::pointer new_connection = TCPConnection::create(acceptor_.get_io_service()); // async_accept(socket, ACCEPT_HANDLER); acceptor_.async_accept(new_connection->socket(), boost::bind(&TCPServer::handle_accept, this, new_connection, boost::asio::placeholders::error)); } void handle_accept(TCPConnection::pointer new_connection, const boost::system::error_code& error) { if (!error) { new_connection->start(); } start_accept(); } boost::asio::ip::tcp::acceptor acceptor_; }; //* tcp_server 에 io_service 를 전달하여 생성하고, tcp_server 클래스를 initiate 한다. //* 메인 스레드에서 tcp_server 에서 사용하는 io_service 의 run() 함수 호출 void server_run() { try { boost::asio::io_service io_service; TCPServer server(io_service); io_service.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } }
'Programming > Boost asio' 카테고리의 다른 글
Daytime.2 - A synchronous TCP daytime server (0) | 2015.04.19 |
---|---|
Daytime.1 - A synchronous TCP daytime client (0) | 2015.04.13 |
Tutorial 5. Synchronising handlers in multithreaded programs (0) | 2015.04.11 |
Tutorial 4. member function handler (0) | 2015.03.17 |
Tutorial 3. Binding arguments to a handler (0) | 2015.03.15 |