2012-03-29 2 views
0

나는 에 새로운 소식입니다. boost :: asio 그래서 내 질문에 어리 석을 수 있습니다. keepalive를 사용하여 비동기 서버 응용 프로그램을 작성했습니다 (단일 연결에서 여러 요청이 전송 될 수 있음).boost :: asio basic_stream_socket :: async_read_some 처리기의 데이터 부분 만 사용합니다.

  • 일정 핸들러 스케줄에서 소켓 -> async_read_some (버퍼 핸들러)

  • 와 읽기 요구 :

    루프 물 :

    연결 제어 루틴은 단순 쓰기 응답은 async_write입니다.

내가 직면하고 문제는 async_read_some에 전달 핸들러가에의 io_service 스레드에 의해 호출 될 때, 버퍼 실제로 하나의 요청보다 더 많은 데이터 (예 : 부분을 포함 할 수 있다는 것이다 클라이언트가 보낸 다음 요청).

나는 그 순간에이 나머지 바이트를 처리하고 싶지 않습니다 (요청의 일부일뿐입니다). 이전 요청을 처리 한 후에 처리하고 싶습니다.

불필요한 remainging 데이터를 다시 소켓으로 재 주입 할 수 있다면이 문제를 쉽게 해결할 수 있습니다. 그래서 그것은 async_read_some 호출에서 처리됩니다.

boost :: asio에 이러한 가능성이 있습니까? 아니면 여분의 코드로 남은 데이터를 저장해야합니까?

답변

4

TCP와 같은 신뢰성 및 정렬 전송을 사용하는 경우이 문제를 다루는 한 가지 방법은하는 것입니다

  1. 이의 나머지 부분을 쓰기 메시지
  2. 의 나머지 부분의 크기를 포함, 알려진 크기의 헤더를 쓰기 메시지

그리고 수신 측에 :

  1. 읽기에 충분한 바이트가를 얻기 위해 그는

    //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ 
    void 
    Connection::readMore() 
    { 
        if (m_connected) 
        { 
         // Asynchronously read some data from the connection into the buffer. 
         // Using shared_from_this() will prevent this Connection object from 
         // being destroyed while data is being read. 
         boost::asio::async_read(
          m_socket, 
          boost::asio::buffer(
           m_readMessage.getData(), 
           MessageBuffer::MESSAGE_LENGTH 
          ), 
          boost::bind(
           &Connection::messageBytesRead, 
           shared_from_this(), 
           boost::asio::placeholders::error, 
           boost::asio::placeholders::bytes_transferred 
          ), 
          boost::bind(
           &Connection::handleRead, 
           shared_from_this(), 
           boost::asio::placeholders::error 
          ) 
         ); 
        } 
    } 
    
    //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ 
    std::size_t 
    Connection::messageBytesRead(const boost::system::error_code& _errorCode, 
              std::size_t _bytesRead) 
    { 
        return MessageBuffer::MESSAGE_LENGTH - _bytesRead; 
    } 
    
    //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ 
    void 
    Connection::handleRead(const boost::system::error_code& _errorCode) 
    { 
        if (!_errorCode) 
        { 
         /// Do something with the populated m_readMessage here. 
         readMore(); 
        } 
        else 
        { 
         disconnect(); 
        } 
    } 
    

    messageBytesRead : ADER

  2. 는 메시지의 나머지 부분과 다음과 같은 어떤 당신이 메시지는 고정 길이 될 것 알고 있다면, 당신이 할 수있는
+0

불행하게도이 가능하지가 :( – losipiuk

+0

@losipiuk 당신은 프로토콜 말을하는지 그래서 현재 양식에 메시지 크기를 나타내는 메타 데이터가 포함되어 있지 않습니다. 메시지의 시작 및 끝 구분 기호가 있습니까? 실제로 메시지가 완료되었다고 어떻게 판단합니까? – hatboyzero

+0

아니오 - 고정 된 크기가 없습니다. 헤더입니다. 실제로 HTTP입니다. – losipiuk

1

뭔가 더 읽기 전체 메시지를 읽었을 때 콜백은 boost::asio::async_read으로 표시됩니다. 이 스 니펫은 코드가 실행중인 기존 Connection 객체에서 가져와서 작동하는 것으로 알고 있습니다 ...

5

당신이 찾고있는 것이 asio::streambuf이라고 생각합니다.

기본적으로, 당신은 실제로했다 consume(amount)에 의해 처리하는 방법을 많이 알려 당신이 맞는 볼만큼 읽기, 숯불 * 같은 시드 streambuf의를 검사하고 있습니다. 클라이언트로 HTTP 헤더를 구문 분석하는 코드 예제 작업

: 프로토콜이 고정되어 나는 그것을 변경할 수 없습니다로

#include <boost/asio.hpp> 
#include <boost/bind.hpp> 
#include <iostream> 
#include <string> 

namespace asio = boost::asio; 

std::string LINE_TERMINATION = "\r\n"; 

class Connection { 
    asio::streambuf _buf; 
    asio::ip::tcp::socket _socket; 
public: 

    Connection(asio::io_service& ioSvc, asio::ip::tcp::endpoint server) 
    : _socket(ioSvc) 
    { 
    _socket.connect(server); 
    _socket.send(boost::asio::buffer("GET/HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")); 
    readMore(); 
    } 

    void readMore() { 
    // Allocate 13 bytes space on the end of the buffer. Evil prime number to prove algorithm works. 
    asio::streambuf::mutable_buffers_type buf = _buf.prepare(13); 

    // Perform read 
    _socket.async_read_some(buf, boost::bind(
      &Connection::onRead, this, 
      asio::placeholders::bytes_transferred, asio::placeholders::error 
    )); 
    } 

    void onRead(size_t read, const boost::system::error_code& ec) { 
    if ((!ec) && (read > 0)) { 
     // Mark to buffer how much was actually read 
     _buf.commit(read); 

     // Use some ugly parsing to extract whole lines. 
     const char* data_ = boost::asio::buffer_cast<const char*>(_buf.data()); 
     std::string data(data_, _buf.size()); 
     size_t start = 0; 
     size_t end = data.find(LINE_TERMINATION, start); 
     while (end < data.size()) { 
     std::cout << "LINE:" << data.substr(start, end-start) << std::endl; 
     start = end + LINE_TERMINATION.size(); 
     end = data.find(LINE_TERMINATION, start); 
     } 
     _buf.consume(start); 

     // Wait for next data 
     readMore(); 
    } 
    } 
}; 

int main(int, char**) { 
    asio::io_service ioSvc; 

    // Setup a connection and run 
    asio::ip::address localhost = asio::ip::address::from_string("127.0.0.1"); 
    Connection c(ioSvc, asio::ip::tcp::endpoint(localhost, 80)); 

    ioSvc.run(); 
} 
+1

+1 이것은 필요한 것처럼 들립니다. – sje397

+0

나는 ASIO-help를 위해 (다른, 그러나 비슷한 요구를 위해) 나 자신을 찾았으며, 이것을 발견했다 : http://think-async.com/Asio/boost_asio_1_3_1/doc/html/boost_asio/overview/core/line_based .html – Rawler

관련 문제