Boost ASIO异步读取一些数据

5

我在实现一个简单的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个字节,并且连接挂起。Web浏览器一直等待响应,服务器也在等待,我不知道它在等什么。
如果取消注释(1),则会读取整个请求(并附加到data_),但它永远不会停止-我必须在浏览器中取消请求,然后才会运行else {}部分-我在stdout上看到我的请求。 问题1:我应该如何处理大型请求?
问题2:我应该如何缓存请求(当前我将缓冲区附加到字符串)?
问题3:我如何知道请求何时结束?在HTTP中总会有一个响应,因此我的Web浏览器会一直等待它并且不关闭连接,但是我的服务器如何知道请求已经完成(并可能关闭它或回复“200 OK”)?
1个回答

9
假设浏览器向您发送了1360字节的数据,您让asio将一些数据读入您的缓冲区,该缓冲区只有32字节。第一次调用时,您的处理程序将被调用,其中包含32字节的数据开头。在这里,如果您注释掉(1),则浏览器尝试发送其余的数据(实际上浏览器已经发送了它,并且它在等待您从中查看的操作系统缓冲区中),您可能会在io_service::run后面被阻塞,直到发生奇迹!
如果您取消注释(1),就像您说的那样,您的循环开始运行,然后读取第一个块,接着是下一个和另一个,直到浏览器发送的数据完成,但之后当您请求asio读取更多数据时,它将等待来自浏览器的数据,而浏览器永远不会再发送任何数据(因为浏览器已经发送了信息并正在等待您的回复),当您从浏览器取消请求时,它将关闭其套接字,然后您的处理程序将被调用,指出无法读取更多数据,因为连接已关闭!!
但是在这里应该做什么才能使其正常工作呢:您应该学习HTTP格式,因此知道浏览器发送给您的数据是什么,并为其提供一个良好的答案,然后您与客户端的通信将继续进行。在这种情况下,缓冲区的结尾是\r\n\r\n,当您看到它时,您不应再读取任何数据,而应处理到目前为止所读取的内容,然后向浏览器发送响应。

如果我只使用HTTP,我会坚持某些结束模式。但是我通常使用TCP,并且我想说它与HTTP的兼容性是偶然的;-) - Queequeg
1
无论我如何描述您的问题,无论使用任何协议,您都应该知道何时倾听和何时发言。在示例浏览器的情况下,等待您的回答可能需要等待奇迹的出现。TCP是一个传输系统而不是协议(当然它也是一个协议,但对于使用原始套接字或想要实现TCP/IP的人来说不是),您应该了解要实现的每个协议的格式,并且没有适用于任何协议的全局解决方案。 - BigBoss
好的。那么发送一个可序列化的对象怎么样,就像在Serialization example中一样。如果我发送一个对象,那么boost会自动处理大小控制吗? - Queequeg
1
在序列化方面,您需要执行两个步骤:首先从套接字中读取数据,然后调用boost::serialization来反序列化缓冲区。因此,首先应确定何时停止读取。对于每个协议,您都应该知道其格式,即使是您为自己的特定目的设计的自定义协议,我也可以提供一个简单的技巧。在发送端将对象序列化为缓冲区,并知道缓冲区的大小,然后嵌入此大小在发送缓冲区的开头,在接收端首先读取大小,然后读取数据,直到指定的大小并进行反序列化!这很简单。 - BigBoss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接