我仍在使用某种客户端与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_read
的boost::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处理程序。一般来说
boost::asio::async_read_until("\r\n\r\n")
Content-Length
header boost::asio::transfer_at_least(content_length)
此外,为什么要期待EOF?连接仍处于打开状态:服务器正在等待另一个SETUP或PLAY请求,并且通常直到RTSP TCP连接超时(根据RFC2326的默认值为60秒)后,才会关闭连接。
如果您已在应用程序中完成与RTSP服务器的交互,请在阅读响应后关闭连接。