我仍在使用某种客户端与IP摄像机进行通信。现在我有以下问题:

我向相机发送了一个请求(尤其是RTSP DESCRIBE)。现在,我得到的答案看起来像这样:

RTSP/1.0 200 OK
CSeq: 2
Date: Thu, Jan 01 1970 00:31:41 GMT
Content-Base: rtsp://192.168.0.42/mpeg4?mode=Live&stream=-1&buffer=0&seek=0&fps=100&    metainfo=/
Content-Type: application/sdp
Content-Length: 517

这是答案的标题,后跟所谓的Session Description,其大小显示在Content-Length字段中。实际上,我不太关心Session Description,我只是对Content-Base字段感兴趣。但是,由于同一套接字上存在一些通信,因此我需要删除所有数据。

为了接收来自async_readboost::asio调用。
我的代码如下所示(简化):
CommandReadBuffer::CallbackFromAsyncWrite()
{
boost::asio::async_read_until(*m_Socket, m_ReceiveBuffer,"\r\n\r\n",
            boost::bind(&CommandReadBuffer::handle_rtsp_describe, this->shared_from_this(),
                    boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
}

由于该标题以空白行终止,因此至少读取该标题(如上所示)。和async_write一样,它只读取更多数据,但没关系。现在转到下一个回调函数:
void CommandReadBuffer::handle_rtsp_describe(const boost::system::error_code& err,size_t bytesTransferred)
{
std::istream response_stream(&m_ReceiveBuffer);
std::string header;
// Just dump the data on the console
while (std::getline(response_stream, header))
{
   // Normally I would search here for the desired content-base field
   std::cout << header << "\n";
}
 boost::asio::async_read(*m_Socket, m_ReceiveBuffer, boost::asio::transfer_at_least(1),
         boost::bind(&CommandReadBuffer::handle_rtsp_setup, this->shared_from_this(),
                            boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

现在这也可以正常工作,如果我打印出接收到的字节数,则始终为215。

现在我们继续进行关键的回调:
void CommandReadBuffer::handle_rtsp_setup(const boost::system::error_code& err, size_t bytesTransferred)
{
std::cout << "Error: " << err.message() << "\n";
    if (!err)
    {
      // Write all of the data that has been read so far.
      std::cout << &m_ReceiveBuffer;

    // Continue reading remaining data until EOF.
    m_DeadlineTimer->async_wait(boost::bind(&CommandReadBuffer::handleTimeout, this->shared_from_this(),boost::asio::placeholders::error));
      boost::asio::async_read(*m_Socket, m_ReceiveBuffer, boost::asio::transfer_at_least(1),
             boost::bind(&CommandReadBuffer::handle_rtsp_setup, this->shared_from_this(),
                                boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
else if (err != boost::asio::error::eof)
{
  std::cout << "Error: " << err.message() << "\n";
}
else
{
    std::cout << "End of Frame " << err.message() << "\n";
}
}

此部分读取220个字节。如果我查看此调用的Console Output并将其与帧的实际有效负载进行比较(如Wireshark所示),我可以看到已接收到所有数据。现在,我实际上假设async_read将给我设置eof错误。但是相反,error的返回码是success,因此它再次调用async_read。这次没有数据要接收,并且它从不调用回调函数(因为将不再有传入的数据)。

现在,我实际上不知道如何确定所有数据都已发送。实际上,我希望设置错误标志。

现在,这与用于异步HTTP客户端的Boost示例的实现非常相似。同样,它也可以通过Example Boost Async HTTP Client来完成。我在另一个电话中实现了这一点,并且在这里确实有效。

现在,在我看来,对于async_read调用,无论是HTTP还是RTSP,都应该没有任何区别-如果没有更多数据可读取,则帧末为帧末。

我也知道根据我正在使用的Boost文档
void async_read(
    AsyncReadStream & s,
    basic_streambuf< Allocator > & b,
    CompletionCondition completion_condition,
    ReadHandler handler);

这意味着该功能将持续到



因此,如果没有更多数据要读取,它将继续。
但是我也尝试了不带CompletionCondition参数的重载函数,该参数应在发生错误时返回(EOF !!!)-但这也不会回调...

有什么建议?我只是不明白我做错了什么...

最佳答案

我已经使用boost asio编写了RTSP客户端和服务器库,可以提供以下建议:
RTSP消息语法是通用的:不需要其他DESCRIBE和SETUP处理程序。一般来说

  • 编写RTSP请求
  • 读取响应做一个boost::asio::async_read_until("\r\n\r\n")
  • 然后检查Content-Length header
  • 如果content_length> 0,则执行
  • 进行boost::asio::transfer_at_least(content_length)

  • 此外,为什么要期待EOF?连接仍处于打开状态:服务器正在等待另一个SETUP或PLAY请求,并且通常直到RTSP TCP连接超时(根据RFC2326的默认值为60秒)后,才会关闭连接。

    如果您已在应用程序中完成与RTSP服务器的交互,请在阅读响应后关闭连接。

    09-11 19:53
    查看更多