boost :: asio :: async_read в блоки boost :: asio :: streambuf, когда streambuf заполняется предыдущим async_read - PullRequest
2 голосов
/ 16 июня 2011

Я искал другие сообщения, но не нашел ничего релевантного. Теперь у меня есть протокол, состоящий из заголовка и тела. Протокол похож на: Z24,91009802,123456789ABCDEF Где Z24, это заголовок. Z - тип сообщения, 24 - оставшиеся байты для чтения. Оставшиеся байты являются переменными, поэтому я читаю до тех пор, пока не будет найдено первое ','.

void handle_handshake(const boost::system::error_code& error)
{
    if (!error)
    {
        boost::asio::async_read_until(
            socket_,
            inputStreamBuffer_,
            ',',
            boost::bind(
                &session::doReadHeader, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred)
        );
    }
    else
    {
        delete this;
    }
}

void doReadHeader(
    const boost::system::error_code& error,
    size_t bytes_transferred)
{
    if (!error)
    {
        istream is(&inputStreamBuffer_);
        vector<char> v(bytes_transferred);
        is.read(&(v[0]),bytes_transferred);
        request_.append(v.begin(),v.end());

        cout << "request_=#" << request_ << "#" << endl;
        int nBytes=string_to_llint(request_.substr(1,request_.size()-2));
        cout << "nBytes=" << nBytes << endl;
        cout << "size=" << inputStreamBuffer_.size() << endl;

        boost::asio::async_read(
            socket_,
            inputStreamBuffer_,
            boost::asio::transfer_at_least(nBytes),
            boost::bind(
                &session::doReadBody, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred)
        );
    }
    else
    {
        delete this;
    }
}

void doReadBody(
    const boost::system::error_code& error,
    size_t bytes_transferred)
{
    if (!error)
    {
        istream is(&inputStreamBuffer_);
        vector<char> v(bytes_transferred);
        is.read(&(v[0]),bytes_transferred);
        request_.append(v.begin(),v.end());

        string response=cardIssueProcessor_.process(request_);
        cout << "request=#" << request_ << "#" << endl;
        cout << "response=#" << response << "#" << endl;
        request_.clear();

        boost::asio::async_write(
            socket_,
            boost::asio::buffer(response, response.size()),
            boost::bind(
                &session::doWriteResponse, this,
                boost::asio::placeholders::error)
        );
    }
    else
    {
        delete this;
    }
}

Теперь заголовок прочитан. Но читая блоки нижнего колонтитула. Видимо, все сообщение читается в заголовке вызова. Когда я выполняю второй async_read () с boost :: asio :: Transfer_at_least (nBytes), nBytes уже находятся в inputStreamBuffer_, но я думаю, что вызов не проверяет это?

Это дамп с вывода:

запрос _ = # Z24, # 24 = число-байт размер = 24

В чем проблема или как я могу ее обойти. Я начинающий толчок, поэтому вся помощь приветствуется. Спасибо.

EDIT: Я попытался проверить заполненность буфера и не вызывать async_read () для тела, если оно уже прочитано предыдущим вызовом. Это вроде работает, но правильное ли это решение?

void doReadHeader(
    const boost::system::error_code& error,
    size_t bytes_transferred)
{
    if (!error)
    {
        istream is(&inputStreamBuffer_);
        vector<char> v(bytes_transferred);
        is.read(&(v[0]),bytes_transferred);
        request_.assign(v.begin(),v.end());

        cout << "request_=#" << request_ << "#" << endl;
        int nBytes=string_to_llint(request_.substr(1,request_.size()-2));
        cout << "nBytes=" << nBytes << endl;
        cout << "size=" << inputStreamBuffer_.size() << endl;

        size_t toReadBytes=nBytes-inputStreamBuffer_.size();
        if (toReadBytes>0)
        {
            boost::asio::async_read(
                socket_,
                inputStreamBuffer_,
                boost::asio::transfer_at_least(toReadBytes),
                boost::bind(
                    &session::doReadBody, this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred)
            );
        }
        else
        {
            doReadBody(error,nBytes);
        }
    }
    else
    {
        delete this;
    }
}

Ответы [ 2 ]

2 голосов
/ 16 июня 2011

Документация Boost ASIO указывает, что вызов async_read_until может считывать данные в буфер, который находится за пределами разделителя (см. Раздел «Примечания»).При этом ваше решение для проверки наличия в буфере большего количества данных является хорошим решением с учетом вашего ввода.

Как я уже упоминал в моем комментарии выше, если ваши требования позволят вам сделать это, используя интегральное значениеоставшиеся байты вместо строки, вероятно, сделают вашу жизнь проще, а код станет чище и менее подвержен ошибкам.

1 голос
/ 16 июня 2011

async_read_until может читать байты после разделителя

Замечания

После успешной операции async_read_until streambuf может содержать дополнительные данные помимо разделителя.Приложение обычно оставляет эти данные в streambuf для последующей операции async_read_until для проверки.

...