[-] Collapse
#include <iostream>
#include <ctime>
#include <string>

#define _WIN32_WINNT 0x0501

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

using boost::asio::ip::tcp;

std::string make_daytime_string()
{
    std::time_t now = std::time( 0 );
    return std::ctime( &now );
}

class Ctcp_connection : public boost::enable_shared_from_this< Ctcp_connection >
{
public:
    typedef boost::shared_ptr< Ctcp_connection > pointer;

    static pointer create( boost::asio::io_service &io )
    {
        return pointer( new Ctcp_connection( io ) );
    }

    tcp::socket &socket()
    {
        return m_socket;
    }

    void start()
    {
        m_message = make_daytime_string();
        // # handle_write 함수에서 매개변수 2가지를 사용할 필요가 없다. 함수 다이어트
//  boost::asio::async_write( m_socket, boost::asio::buffer( m_message ),
//  boost::bind( &Ctcp_connection::handle_write, shared_from_this(),
//  boost::asio::placeholders::error,
//  boost::asio::placeholders::bytes_transferred) );

        std::cout << "5-1 prepare async write" << std::endl;

        boost::asio::async_write( m_socket, boost::asio::buffer( m_message ),
            boost::bind( &Ctcp_connection::handle_write, shared_from_this() ) );

        std::cout << "5-2 send daytime to client and binding" << std::endl;
    }

private:
    Ctcp_connection( boost::asio::io_service &io )
        : m_socket( io )
    { }

// void handle_write( boost::asio::placeholders::error_code & /*error*/,
//  size_t /*bytes_transferred*/ )
// { }

    void handle_write()
    { }

    tcp::socket     m_socket;
    std::string     m_message;      // char[] or std::vector도 사용 가능
};

class Ctcp_server
{
public:
    Ctcp_server( boost::asio::io_service &io )
        : m_acceptor( io, tcp::endpoint( tcp::v4(), 13 ) )
    {
        std::cout << "1 call creater" << std::endl;
        start_accept();
    }

private:
    void start_accept()
    {
        std::cout << "2 call start accept func" << std::endl;

        Ctcp_connection::pointer new_connection = Ctcp_connection::create( m_acceptor.io_service() );

        std::cout << "3 prepare async" << std::endl;

        m_acceptor.async_accept( new_connection->socket(), boost::bind( &Ctcp_server::handle_accept,
            this, new_connection, boost::asio::placeholders::error ) );

        std::cout << "4 async complete and binding\n --Wait Connect" << std::endl;
    }

    void handle_accept( Ctcp_connection::pointer new_connection, const boost::system::error_code &error )
    {
        if( !error )
        {
            std::cout << "5 start handle_accept" << std::endl;
            new_connection->start();
            std::cout << "6 call start_accept func" << std::endl;
            start_accept();
        }
    }

    tcp::acceptor   m_acceptor;
};

int main()
{
    try
    {
        boost::asio::io_service io;
        Ctcp_server server( io );
        io.run();
    }
    catch( std::exception &e )
    {        std::cerr << e.what() << std::endl;
    }

    return 0;
}
출력된 결과


중간 --Wait Connect 라는 부분은 Client로 접속하기 전까지 대기 상태로 유지된다.
5번부터 4번까지( 5 -> 5-1 -> 5-2 -> 6 -> 2 -> 3 -> 4 ) Client 가 접속될때 실행되는 부분이다.

소스를 조금 분석하자면,
m_acceptor.async_accept( 소켓, bind( 연결할 함수 포인터 ) );
프로그램이 흐르다가 이 부분을 만나면 무작정 대기에 빠진다. 물론 async이기 때문에 다른 작업이 가능하다.
상단의 소스에는 thread를 쓰고 있지 않기에 무한대기 상태에 빠진것처럼 보인다.

다시 말하자면, 명시된 소켓으로 Client가 접속이 될때까지 binding된 콜백함수를 호출하지 않는 것이다.

클라이언가 접속이 되면( 즉, accept 가 되면) 바인딩된 함수로 호출이 되는것이다. 그 전까지는 함수를 호출하지 않는다. )

5-1과 5-2 사이에도 async_write 함수가 있는데 이것 역시 같은 맥락일 것이라 예상된다.이 부분은 나중에 thread를 추가 하고 나서 다시 한번 테스트. 하지만, asio의 흐름상 비슷할거라 생각된다. 명시된 소켓으로 패킷을 날리는데, 다 날라갈때까지 대기를 하고 다 날라간 이후엔 binding된 콜백함수를 호출한다.

소스에는 호출되는 콜백함수( Ctcp_connection::handle_write )는 내부가 비어 있기 때문에 아무 처리를 안 한다.
이론적으로 흐름을 잡자면, handle_write를 5-3이라 한다면, 5-1 -> 5-3 -> 5-2 이 될것이다.
만약 보낼 패킷의 양이 많아 async 상태가 된다면 5-1 -> 5-2 -> 처리가 끝날때 까지그외에 다른 부분 -> 5-3 이 될것이다.

하나의 Client가 접속을 하고 daytime을 받아간후 6번을 지나면 다시 2번으로 돌아간다.
여기서 다시 async_accept에서 대기.

요기까지 개인적으로 분석한 Asio Tutorial 중 Daytime.3 - An asynchronous TCP daytime server 부분이다.

post script.
cout으로 번호랑 주석 비스므리하게 출력한건 분석하기 위해 임의로 추가한 부분입니다.

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

asio -- 1  (0) 2009.12.01
Bind 공부중인거 정리. < 01 >  (0) 2009.08.20
Signal 공부중인거 정리. < 04 >  (0) 2009.08.20
Signal 공부중인거 정리. < 03 >  (0) 2009.08.20
Signal 공부중인거 정리. < 02 > - 1  (0) 2009.08.19