Ускорить ASIO async_read_some

У меня возникли трудности с реализацией простого TCP-сервера. Следующий код взят из примеров boost::asio, точнее "Http Server 1".

void connection::start() {
    socket_.async_read_some(
            boost::asio::buffer(buffer_),
            boost::bind(
                &connection::handle_read, shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred
            )
        );
}
void connection::handle_read(const boost::system::error_code& e, std::size_t bytes_transferred) {
        if (!e && bytes_transferred)    {
                std::cout << " " << bytes_transferred <<"b" << std::endl;
                data_.append(buffer_.data(), buffer_.data()+bytes_transferred);

                //(1) what here?                
                socket_.async_read_some(
                    boost::asio::buffer(buffer_), 
                    boost::bind(
                        &connection::handle_read, shared_from_this(),
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred
                    )
                ); 

            }
            else// if (e != boost::asio::error::operation_aborted)
            {
                std::cout << data_ << std::endl;
                connection_manager_.stop(shared_from_this());
            }
        }

В исходном коде buffer_ достаточно большой, чтобы сохранить весь запрос. Это не то, что мне нужно. Я изменил размер на 32 байта.

Сервер компилирует и прослушивает порт 80 локального хоста, поэтому я пытаюсь подключиться к нему через веб-браузер.

Теперь, если оператор (1) закомментирован, то читаются только первые 32 байта запроса и соединение зависает. Веб-браузер продолжает ждать ответа, сервер ждет... Я не знаю что.

Если (1) не закомментирован, то весь запрос читается (и добавляется к data_), но он никогда не останавливается — мне нужно отменить запрос в моем браузере, и только тогда запускается часть else { } — я вижу свой запрос на стандартном выходе.

Вопрос 1. Как мне обработать большой запрос?
Вопрос 2. Как мне кэшировать запрос (в настоящее время я добавляю буфер к строке)?< br/> Вопрос 3: Как узнать, что запрос выполнен? В HTTP всегда есть ответ, поэтому мой веб-браузер продолжает ждать его и не закрывает соединение, но как мой сервер может узнать, что запрос завершен (и, возможно, закрыть его или ответить «200 OK»)?


person Queequeg    schedule 16.09.2012    source источник


Ответы (1)


Предположим, что браузер отправляет вам 1360 байт данных, вы говорите asio, чтобы прочитать некоторые данные в ваш буфер, который, как вы говорите, имеет только 32 байта. тогда в первый раз, когда вы его вызовете, ваш обработчик будет вызываться с 32-байтовым началом данных. здесь, если вы прокомментируете (1), тогда браузер попытается отправить остальные свои данные (на самом деле браузер уже отправил их, и они находятся в буфере ОС, который ждет, пока вы их оттуда заглянете), и вы, возможно, заблокированы за io_service::run для какого-то чуда! !

если вы раскомментируете (1), как вы говорите, что ваш цикл начался, вы читаете первый блок, затем следующий и еще один и ... до тех пор, пока данные, отправленные браузером, не закончатся, но после этого, когда вы скажете asio, чтобы прочитать еще некоторые данные, он будет ждать для некоторых дополнительных данных, которые никогда не поступают из браузера (поскольку браузер уже отправил свою информацию и ждет вашего ответа), и когда вы отмените запрос из браузера, он закроет свой сокет, а затем будет вызван ваш обработчик с ошибкой, которая сказать, что я не могу прочитать больше данных, так как соединение закрыто.!!

но то, что вы должны сделать здесь, чтобы заставить его работать, это: вы должны изучить формат HTTP и, таким образом, знать, какие данные отправил вам ваш браузер, и дать на них хороший ответ, и тогда ваше общение с клиентом будет продолжено. в этом случае конец буфера равен \r\n\r\n, и когда вы его увидите, вам больше не нужно читать данные, вы должны обработать то, что вы прочитали до сих пор, а затем отправить ответ браузеру.

person BigBoss    schedule 16.09.2012
comment
Если бы я только использовал HTTP, я бы придерживался какого-то конечного шаблона. Но я использую TCP в целом, и я бы сказал, что он случайно работает с HTTP ;-) - person Queequeg; 17.09.2012
comment
на всякий случай описываю вашу проблему, в любом протоколе надо знать когда слушать а когда говорить. в ситуации браузера примера ждите вашего ответа и, возможно, ждите чуда. TCP - это транспортная система, а не протокол (конечно, это протокол, но не для вас или меня для тех, кто использует сырые сокеты или хочет внедрить TCP/IP), и вы должны знать формат каждого протокола, который вы хотите реализовать, и там нет глобального решения, которое работает с любым протоколом - person BigBoss; 17.09.2012
comment
в случае сериализации у вас есть 2 шага: сначала) прочитать данные из сокета, а затем) вызвать boost::serialization для десериализации буфера. поэтому сначала вы должны знать, когда перестанете читать. это когда я говорю, что для каждого протокола вы должны знать его формат, даже для пользовательского протокола, который вы разрабатываете для своих собственных целей, я могу посоветовать простой трюк. на стороне отправки сериализуйте объект в буфер, и вы знаете размер буфера, затем вставьте этот размер в начало буфера отправки, а на стороне приема сначала прочитайте размер, а затем прочитайте данные до указанного размера и десериализуйте его !! это просто - person BigBoss; 19.09.2012