Daytime.3 - An asynchronous TCP daytime server

Programming/Boost asio 2016.04.03 23:09

다음에 기반함

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;
  }
}



저작자 표시 비영리 변경 금지

Learn You Some Erlang

Programming/Erlang 2016.03.09 00:53

몰랐는데, 

learn you ~ 

시리즈북이 원래 있었나보다. (하스켈도 있다고 그러고. )


근래에 몇달째 functional programming 과 Rx 쪽으로 스터디가 집중되다보니, 

말이 펑셔널 펑셔널 하게 짠다지, 좀 잘해보려면 공부를 많이 해야할 것 같아서 .. (현업에서 쓰고있는 부분은 없으니... )

learn You some erlang

http://learnyousomeerlang.com/


을 팀내에서 세미나 형태로 공유하고 있다. - 라고 쓰고 그냥 팀분들께 하는 사기극일지도..-


내용을 잘 정리해서 블로깅을 하거나,  아예 제대로 ? 한글로 번역 - 해서 출판하고 싶은 욕망이 샘솟긴 하는데.. 

(출판할 수 있을까 ? - 이 끝없는 명예욕....) 


일단은 급한대로 한주 한주 세미나를 진행하는 것으로 만족. 


다음 github repo 에 매주 발표자료를 업로드 하고 있다. 

https://github.com/nolleh/learnyouerlang


다음은 1주차 내용.

https://github.com/nolleh/learnyouerlang/blob/master/week1/week1.pdf


뭔가....첨엔 뭐이렇게 문법이 직관적이지가 않아.. 라고 했다가.. 

6주째 자료를 만드는 지금은

얼랭 짱짱맨인듯...


저작자 표시 비영리 변경 금지

'Programming > Erlang' 카테고리의 다른 글

Learn You Some Erlang  (0) 2016.03.09

설정값

개발툴/SubmlimeText 2016.01.13 14:25

항목설명
theme레이아웃 테마
color_scheme문자 색상 테마
font-face글꼴
font-size글꼴 크기
teb_size탭 간격
word_wraptrue(자동 줄 바꿈 사용) / false(자동 줄 바꿈 미 사용)
draw_white_space탭, 공백 시각화하기
translate_tabs_to_spacestrue(스페이스) / false(탭)
trim_trailing_white_space_on_save저장 시 줄끝 공백 제거
ensure_newline_at_eof_on_save저장 시 문서 마지막 줄에 빈 줄없으면 추가
default_line_ending줄바꿈 문자 형식 지정(system, windows, unix)
rulers지정한 가로 문자열 위치에 라인 표시
highlight_line현재 줄 강조
fade_fold_buttonstrue(코드 접기 미 사용) / false(코드 접기 사용)
bold_folder_labelstrue(폴더 굵게 표시) / false(폴더 굵게 표시)
caret_style커서 스타일("solid","wide","blink", "phase", "smooth")
highlight_modified_tabs변경된 파일 탭 색상 표시 true/false
line_padding_top줄 간격 상단 여백
line_padding_bottom줄 간격 하단 여백
always_show_minimap_viewport미니맵에서 현재 위치 시각화하기
draw_minimap_border미니맵 현재 위치 시각화에 테두리 표기하기


저작자 표시 비영리 변경 금지

'개발툴 > SubmlimeText' 카테고리의 다른 글

설정값  (0) 2016.01.13
Sublime Repl with scheme  (0) 2015.08.10
[Sublime Text 2] C# 에서 주석처리가 되지 않을때  (0) 2014.08.18
SublimeText Tabs > space  (0) 2014.08.13
1 2 3 4 5 ... 43


티스토리 툴바