[-] 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
asio -- 1 Programming/Boost 2009. 12. 1. 12:23
[-] Collapse
#define _WIN32_WINNT 0x0501

#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

int main()
{
    boost::asio::io_service io;
    boost::asio::deadline_timer t( io, boost::posix_time::seconds( 10 ) );

    std::cout << "test" << std::endl;

    t.wait();       // 10초 동안 대기. blocking

    std::cout << "ttttt" << std::endl;
}
블록모드. 10초동안 대기를 명하고, wait를 만나게 되면 10초동안 말 그대로 wait(대기) 한다. 만약 wait 명령어를 호출 해주지 않는다면, 그냥 패스~

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

asio - TCP_server( async )  (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
/*      이 녀석이 하는 짓      */

어떠한 함수로 인자들의 값을 넘겨주는것 같음.
정확히 어디서 쓰이는건지 이해가 아직은 안되고 있음.

우선 사용법.

bind( 함수명, (상수 값 or 파라메터 인덱스)~ 쭉 ) ( 아규먼트 )


ex)
boost::bind( func, 1, _1, 2, _3, _2 ) ( 10, 11, 12 );
 == func( 1, 10, 2, 12, 11 ); 와 같다.

// 단, func라는 함수는 다섯개의 인자를 받는 함수여야 함.
// 인자수가 적거나 많으면 컴파일 에러

// function 이나 signal과 연동해서 쓰는법.
int Func( int x, int y )
{
      do something;
      return 0;
}

// 함수의 원형과 같이 펑션과 시그널을 잡아줌. 리턴형 int, 파라메터 int 2개
boost::function< int( int, int ) > f01;
boost::signal< int( int, int ) > s01;

// 인자로 아규먼트를 받도록 구현
f01 = boost::bind( Func, _1, _2 );

boost::signals::connection c01 = s01.connect( boost::bind( Func, _1, _2 ) );
// boost::signals::connection c01 = s01.connect( f01 );  // 위에랑 동일

cout << f01( 10, 20 ) << " " << s01( 20, 30 ) << endl;

//---------------------------------------------------
// 멤버함수를 연결하는 법
struct X {
 int F( int );
};

X x;

boost::bind( $X::F, _1, _2 ) ( x, 10 );

// Function을 써서 사용한 방법. 결과는 위와 동일.
boost::function< int( X*, int ) > f01;
f01 = boost::bind( $X::F, _1, _2 );
f01( &x, 10 );

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

asio - TCP_server( async )  (0) 2009.12.01
asio -- 1  (0) 2009.12.01
Signal 공부중인거 정리. < 04 >  (0) 2009.08.20
Signal 공부중인거 정리. < 03 >  (0) 2009.08.20
Signal 공부중인거 정리. < 02 > - 1  (0) 2009.08.19
/*     boost connection에 관한 부분     */

boost::signal< void() > sig01;
// signal 이 아니고 signals 임. 주의. 게다가 connection 대문자로 쓰면 다른 의미의 컨넥션이 됨.
boost::signals::connection c01;

// connect 함수의 리턴값이 바로 컨넥션
c01 = sig01.connect( Func() );

// 연결 여부를 리턴하는 함수
if( c01.connected() ) {
    sig01();
}

/*
* boost::connection 헤더에 정의된 모냥
*  // Returns true if the signal and slot are connected
*  bool connected() const { return con.get() && con->signal_disconnect; }
*/

c01.disconnect();      // 연결 끊기

c01.block();              // 임시로 블럭.
c01.unblock();          // 블럭해제

{
    int a02 = 10;
// sig01.connect( Func() );
    boost::signals::scoped_connection c02 = sig01.connect( Func() );
    sig01();
}
// scoped_connection으로 연결했던 signal 이라면 실행되지 않는다.
// 단, scoped 가 아니면 지역변수로 만들었더라도 실행이 된다.
sig01();
cout << a02 << endl;           // 물론 컴파일 에러. a02를 못 찾는다.



ps. 만약 signal 생성시 리턴값이 있는 signal을 만들면
disconnection 이나 block 이후 시그널 호출시 오류가 남.
ex) boost::signal< int() > sig01;
boost::signals::connection c01 = sig01.connect( Func() );

c01.disconnect();   or      c01.block();
sig01();           -- 에러 발생

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

asio -- 1  (0) 2009.12.01
Bind 공부중인거 정리. < 01 >  (0) 2009.08.20
Signal 공부중인거 정리. < 03 >  (0) 2009.08.20
Signal 공부중인거 정리. < 02 > - 1  (0) 2009.08.19
Signal 공부중인거 정리. < 02 >  (0) 2009.08.19
/*    간단한 함수를 소개    */

boost::signal< void() > sig01;

sig01.connect( 1, Func1() );
sig01.connect( 0, Func2() );

실행결과
Func2()
Func1()

// 컨넥시 인덱스를 넣어주면 자동으로 인덱스 순으로 정렬이 된다.

//-----------------------------------
void Func1( Arg ) {
   to do 1
}
void Func2( Arg ) {
   to do 2
}
void Func3( Arg ) {
   to do 3
}

boost::signal< void( Arg ) > sig02;

sig02.connect( &Func1 );
sig02.connect( &Func2 );
sig02.connect( &Func3 );

sig02( arg );

실행결과
to do 1
to do 2
to do 3

// 컨넥이 된 모든 함수로 arg를 보낸다. 그리고 각 함수가 실행됨.

//-----------------------------------
int Func4( Arg ) {
    return 4;
}
int Func5( Arg ) {
    return 5;
}

// 연결된 함수의 리턴값이 int인 것을 주의
boost::signal< int( Arg ) > sig03;

sig03.connect( &Func4 );
sig03.connect( &Func5 );

cout << sig03( Arg ) << endl;

실행결과
5

// Func4 에서 리턴 4를 하지만 Func5 에서 다시 5를 리턴하므로 결과는 5!! 빠밤!
/*     오버로드 된 멤머 함수를 컨넥시 오류 나는 부분~     */
// 태인이형 알려주셔서 캄샤캄샤~

struct stFunc
{
     void Display() {
           // to do
     }
     void Display_text( const char* pszText ) const {
           // to do
     }
     void Display_text() const {
           // to do
     }
};

boost::signal< void( stFunc*, const char* ) > sig01;
boost::signal< void( stFunc* ) > sig02;

stFunc* pFunc = new stFunc;

/*
* 일반적인 모양
*  sig01.connect( &stFunc::Display_text );
*  오버로드된 멤버 함수를 컨넥할 시
*  sig01.connect( static_cast< 리턴형( 구조체나 클래스명::*)( 인자 ) > ( 연결할 멤버함수의 주소 )
*/

sig01.connect( static_cast< void( stFunc::* )( const char* ) const > ( &stFunc::Display_text ) );
sig02.connect( static_cast< void( stFunc::* )() const > ( &stFunc::Display_text ) );

sig01( pFunc, "테스트 문자열" );
sig02( pFunc );

delete pFunc;