2011-09-02 1 views
0

boost::asio::socket을 사용하여 RTMP 프로토콜을 구현 중입니다.블로킹 또는 비동기 boost :: asio :: socket을 사용하여 프로토콜 핸드 셰이크 구현 읽기/쓰기

async_accept 후에 프로토콜에 3 단계 핸드 셰이크가 필요합니다. 그렇지 않은 경우는 false (연결이 아직 처리하지 중단), 핸드 쉐이크가 (다음 RtmpConnection :: HandleData가 호출됩니다) 성공했을 경우

. 
. 
. 
void RtmpServer::StartAsyncAccept() 
{ 
    // Create a new connection 
    nextConn = RtmpConnection::Create(this, ios); 

// FIXME: shall we use async or blocking accept??? 
    acceptor.async_accept 
    (
     nextConn->GetSocket(), 
     boost::bind 
     (
      &RtmpServer::HandleAsyncAccept, 
      this, 
      boost::asio::placeholders::error 
     ) 
    ); 
} 
. 
. 
. 
void RtmpServer::HandleAsyncAccept(const boost::system::error_code& ec) 
{ 
    if (!ec) 
    { 
     if (nextConn->StartHandshake()) 
     { 
      // Push the current connection to the queue 
      AddConnection(nextConn); 

      boost::array<char, 0> dummyBuffer; 
      nextConn->GetSocket().async_read_some 
      (
     // TODO: use a strand for thread-safety. 
       boost::asio::buffer(dummyBuffer), // FIXME: Why boost::asio::null_buffers() not working? 
       boost::bind 
       (
        &RtmpConnection::HandleData, 
        nextConn, 
        boost::asio::placeholders::error 
       ) 
      ); 
     } 
    } 

    // Start to accept the next connection 
    StartAsyncAccept(); 
} 

RtmpConnection::StartHandshake는 true를 돌려줍니다 : 아래의 코드를 참조하십시오.

핸드 셰이크에는 세 가지 주요 단계가 있으며 각각 Cx 및 Sx 메시지가 포함됩니다 (예 : C{0,1,2}, S{0,1,2}).

기본 악수 따라야합니다

// HANDSHAKE PROTOCOL 
// Handshake Sequence: 
// The handshake begins with the client sending the C0 and C1 chunks. 
// 
// The client MUST wait until S1 has been received before sending C2. 
// The client MUST wait until S2 has been received before sending any 
// other data. 
// 
// The server MUST wait until C0 has been received before sending S0 and 
// S1, and MAY wait until after C1 as well. The server MUST wait until 
// C1 has been received before sending S2. The server MUST wait until C2 
// has been received before sending any other data. 

당신이 (평소처럼), 악수은 기다려야합니다, 것으로 나타났습니다 수 있기 때문이다. 예 :

서버는 S0을 보내기 전에 util C0을 수신해야합니다. 우리의 경우 C0은 1 바이트 버전의 정수만 포함하고 서버는 버전이 유효한지 확인한 다음 S0을 클라이언트에 보냅니다.

등등, C1/S1, C2/S2와 비슷합니다 (그러나 약간 다릅니다).

제 질문은이 핸드 셰이크에 대한 읽기/쓰기 차단을 사용해야합니까, 아니면 비동기입니까?

현재 구현하기가 쉬운 읽기/쓰기 차단 기능을 사용하고 있습니다.

그러나 많은 사람들이 비동기 읽기/쓰기를 제안한다는 사실을 알게되었습니다. 더 나은 성능과 유연성이 있기 때문입니다.

비동기 소켓 읽기/쓰기를 사용하여 구현하려는 경우 어떻게해야합니까? 이 3 가지 주요 단계에 대한 핸들러를 만들어야합니까? 또는 다른 좋은 제안.

의사 코드 샘플을 보내 주시면 감사하겠습니다.

답변

0

일반적인 두 가지 방법은 다음과 같습니다

  1. 비동기. 스레드 수가 적은 작업
  2. 동기화. 연결/클라이언트 당 하나의 쓰레드로 작업한다.

확장 성 측면에서 보면 (1) 비트가 2이지만 코드의 단순성 측면에서 볼 때 일반적으로 (2)가 (1)과 비슷하다는 것이 잘 알려져 있다고 생각한다. 몇 가지 연결 이상을 처리 할 것으로 예상되지 않으면 (2)를 고려할 수 있습니다.

코 루틴을 사용하여 비동기 코드를 동기식으로 만들 수 있으며 두 가지 장점을 모두 활용할 수 있습니다. 그러나 플랫폼 독립적 인 방법으로는 수행 할 수 없으며 표준 방법이 없기 때문에 상당히 복잡 할 수 있습니다. 나는 그것이 매우 자주 행해지 지 않는다고 생각한다.

비동기를 사용하는 간단한 방법 중 하나. 작업은 소켓에서 읽거나 소켓에 쓰는 데 더 많은 데이터가있을 때 콜백이 사용되는 암시 적 상태 시스템을 갖는 것입니다.그러면 다음과 같이 표시됩니다.

class my_connection { 
    tcp::socket m_sock; 
    char m_buf[1024]; 
    int m_pos; 

    void async_handshake(size_t bytes_transferred, error_code& ec) { 
     if (ec) { ... } 
     m_pos += bytes_transferred; 

     if (m_pos == handshake_size) { 
     parse_handshake(); 
     return; 
     } 

     m_sock.async_read(asio::buffer(m_buf + m_pos, handshake_size - m_pos), boost::bind(&async_handshake, shared_from_this(), _1, _2)); 
    } 

    void parse_handshake() 
    { 
     // ... 
     m_pos = 0; 
     // ... fill m_buf with handshake ... 
     async_write_handshake(); 
    } 

    void async_write_handshake(size_t bytes_transferred, error_code& ec) { 
     if (ec) { ... } 
     m_pos += bytes_transferred; 

     if (m_pos == handshake_size) { 
     handshake_written(); 
     return; 
     } 

     m_sock.async_write_some(asio::buffer(m_buf + m_pos, handshake_size - m_pos), boost::bind(&async_write_handshake, shared_from_this(), _1, _2)); 
    } 

    void handshake_written() { /* ... */ } 
}; 

프로토콜이 복잡 해지더라도 지속성이 떨어질 수 있습니다. 이를 처리하기 위해 연결 클래스에 명시적인 상태 시스템을 포함하는 것이 더 간단 할 수 있으며 단일 읽기 콜백과 단일 쓰기 콜백이 있습니다. 일부 데이터를 쓰거나 읽을 때마다 연결 상태에 따라 작업을 수행합니다.

+0

답장을 보내 주셔서 감사합니다. 확실히, 내 서버가 100 개 이상의 연결을 동시에 수용 할 것으로 예상되므로 (1)을 사용해야합니다. 연결 당 하나의 스레드가 잘 확장되지 않습니다. 작성한 샘플 코드는 현재 비동기로 전환하면 수행 할 계획이지만, 구현하기에는 지루한 일입니다. 핸드 셰이크에는 3 단계가 필요하기 때문에 많은 핸들러가있을 것입니다. BTW, 나에게 상태 머신에 대한 더 많은 정보를 소개하고 단일 읽기/쓰기 콜백을 구현하는 방법은 무엇입니까? 감사. –

+0

libtorrent에서 피어 연결 객체를 살펴볼 수 있습니다. http://libtorrent.svn.sourceforge.net/viewvc/libtorrent/trunk/src/bt_peer_connection.cpp?revision=5948&view=markup 여기서 asio는 asio 위에 조금 더 추상화되어 있습니다. 보내기/받기 버퍼와 비동기 읽기 및 쓰기를 다시 시작하는 기본 연결 객체가 있습니다. 속도 제한 지원으로 인해 코드가 좀 더 복잡해졌습니다. 즉, 연결에 대역폭 할당량이 맞지 않아 읽기 또는 쓰기가되지 않는 경우가 있습니다. – Arvid

관련 문제