【问题标题】:Boost ASIO async_read_some提升 ASIO async_read_some
【发布时间】:2012-09-16 18:41:02
【问题描述】:

我在实现一个简单的 TCP 服务器时遇到了困难。以下代码取自boost::asio examples,确切地说是“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 字节。

服务器编译并监听 localhost 的 80 端口,所以我尝试通过我的网络浏览器连接到它。

现在如果语句 (1) 被注释掉,那么只有请求的前 32 个字节被读取并且连接挂起。 Web 浏览器一直在等待响应,服务器确实在等待。我不知道是什么。

如果 (1) 未注释,则读取整个请求(并添加到 data_),但它永远不会停止 - 我必须在浏览器中取消请求,然后才会运行 else { } 部分 -我在标准输出上看到了我的请求。

问题 1: 我应该如何处理大请求?
问题 2: 我应该如何缓存请求(目前我将缓冲区附加到字符串) ?
问题 3:如何判断请求已结束?在 HTTP 中总是有响应,所以我的网络浏览器一直在等待它并且没有关闭连接,但是我的服务器如何知道请求已经结束(可能关闭它或回复一些“200 OK”)?

【问题讨论】:

    标签: c++ networking boost boost-asio


    【解决方案1】:

    假设浏览器向您发送 1360 字节的数据,您说 asio 将一些数据读入您的缓冲区,您说它只有 32 字节。 然后第一次调用它时,您的处理程序将以 32 字节的数据开头调用。在这里,如果您评论 (1),那么浏览器会尝试发送其其余数据(实际上浏览器已经发送了它,并且它在操作系统缓冲区中等待您从那里偷看)并且您可能被 io_service::run 阻止了一些奇迹!!

    如果您在说循环开始时取消注释 (1),则读取第一个块,然后读取下一个块,然后...直到浏览器发送的数据完成,但之后当您说 asio 读取一些更多数据它将等待更多从未来自浏览器的数据(因为浏览器已经发送了它的信息并正在等待您的回答)并且当您取消来自浏览器的请求时,它将关闭其套接字,然后您的处理程序将调用时出现一个错误,说我无法读取更多数据,因为连接已关闭。!!

    但你应该在这里做的是:你应该学习HTTP格式,从而知道你的浏览器发送给你的数据是什么,并为它提供一个好的答案,然后你与客户的沟通将进行。在这种情况下,缓冲区的结尾是\r\n\r\n,当您看到它时,您不应该再读取任何数据,您应该处理您到目前为止读取的内容,然后向浏览器发送响应。

    【讨论】:

    • 如果我只使用 HTTP,我会坚持一些结束模式。但我一般都在使用 TCP,我会说它偶然与 HTTP 一起使用 ;-)
    • 无论如何我描述你的问题,在任何协议中你都应该知道什么时候听,什么时候说。在示例浏览器的情况下,等待您的回答,您可能会等待奇迹。 TCP 是一个传输系统而不是一个协议(当然它是一个协议,但对于那些使用原始套接字或想要实现 TCP/IP 的人来说,它不适合你或我)并且你应该知道你想要实现的每个协议的格式并且在那里没有适用于任何协议的全局解决方案
    • 好的。发送一个可序列化的对象怎么样,比如Serialization example。如果我发送一个对象,那么 boost 会自动处理大小控制吗?
    • 在序列化的情况下,您有两个步骤:首先)从套接字读取数据,然后)调用 boost::serialization 以反序列化缓冲区。所以首先你应该知道什么时候停止阅读。这就是当我说对于每个协议你应该知道它的格式时,即使对于你为自己的目的设计的自定义协议,我可以建议一个简单的技巧。在发送端将对象序列化到缓冲区中,并且您知道缓冲区的大小,然后将此大小嵌入发送缓冲区的开头,并在接收端首先读取大小,然后将数据读取到指定大小并反序列化!很简单
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多