Boost async_read 不会给我一个“帧结束”的信息。旗帜
我仍在开发某种与 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-Base
字段感兴趣。但是,由于同一套接字上有一些通信,我需要删除所有数据。
为了接收,我使用来自 boost::asio
的 async_read
调用。 我的代码看起来(简化)如下:
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 字节。如果我查看此调用的控制台输出并将其与帧的实际有效负载进行比较(如 Wireshark 中所示),我可以看到所有数据均已收到。现在我实际上假设 async_read
会给我设置 eof
错误。但 error
的返回码是 success
,因此它再次调用 async_read
。这次没有数据被接收,并且它永远不会调用回调函数(因为不会再有传入的数据)。
现在我实际上不知道如何确定所有数据都已发送。实际上我希望设置错误标志。
现在,这与异步 HTTP 客户端的 Boost 示例的实现非常相似。在 Boost 异步 HTTP 客户端示例。我在另一个电话中实现了这一点,并且它确实有效。
现在,我认为,无论是 HTTP 还是 RTSP,对于 async_read
调用都没有什么区别 - 如果没有更多数据可供读取,则帧结束就是帧结束。
我还知道根据我正在使用的 boost 文档,
void async_read(
AsyncReadStream & s,
basic_streambuf< Allocator > & b,
CompletionCondition completion_condition,
ReadHandler handler);
这意味着该功能将持续到
提供的缓冲区已满(即已达到最大大小)。 completion_condition 函数对象返回 0。
因此,如果没有更多数据可供读取,它就会继续。 但我也尝试了没有 CompletionCondition
参数的重载函数,该函数应该在发生错误时返回( EOF
!!!) - 但这也不会回调.. 有什么建议吗
?我只是不明白我做错了什么......
I'm still working on some kind of client for communication with an IP Camera. Now I have the following issue:
I send a request to the camera ( a RTSP DESCRIBE
in particular ). Now I get it's answer which looks like this:
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
This is the header of the answer, followed by a so called Session Description
which has the size shown in the field Content-Length
. Actually I don't care much for the Session Description
, I'm just interested in the Content-Base
field. But still, since there is some communication following on the same socket, I need to get rid of all the data.
For receiving'm using the async_read
calls from boost::asio
.
My code looks ( simplified ) like this:
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));
}
This one reads at least the header ( shown above ) since its terminated by a blank line. As usual for async_write
it just reads some more of the data, but nevermind. Now to the next callback function:
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));
}
Now this works fine as well, if I print out the number of received bytes it's always 215.
Now we go on to the critical callback:
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";
}
}
This part reads 220 Bytes. If I look at console Output from this call and compare it with the actualy payload of the frame ( as seen in Wireshark ) I can see that all data has been received. Now I would actually assume that async_read
would set me the eof
error. But instead the return code of error
is success
and so it calls async_read
again. This time there is no data to be received and it never calls the callback function ( since there will be no more incoming data ).
Now I actually don't know how I could determine that all data has been sent. Actually I would expect the error flag to be set.
Now this is very similar to the implementation of the Boost Example for an Async HTTP client. Also it is done the same way in the Example Boost Async HTTP Client. I implemented this in another call and there it actually works.
Now in my opinion it should make no difference for the async_read
call wether it is HTTP or RTSP - end of frame is end of frame, if there is no more data to read.
I'm also aware that according to the boost documentation I am using
void async_read(
AsyncReadStream & s,
basic_streambuf< Allocator > & b,
CompletionCondition completion_condition,
ReadHandler handler);
which means the function will continue until
The supplied buffer is full (that is, it has reached maximum size). The completion_condition function object returns 0.
So if there is no more data to read, it just continues.
But I also tried the overloaded function without the CompletionCondition
parameter, which should return when an error occurs ( EOF
!!! ) - But this just won't callback either...
Any suggestions? I just don't get what I'm doing wrong...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我使用 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。
如果在您的应用程序中,您已完成与 RTSP 服务器的交互,请在读取响应后关闭连接。
I have written an RTSP client and server library using boost asio and can offer the following advice:
The RTSP message syntax is generic: there is no need for different DESCRIBE and SETUP handlers. In general
boost::asio::async_read_until("\r\n\r\n")
Content-Length
headerboost::asio::transfer_at_least(content_length)
Further, why are you expecting an EOF? The connection is still open: the server is waiting for either another SETUP or a PLAY request and typically won't close the connection until the RTSP TCP connection has been timed out, which has a default value of 60 seconds according to RFC2326.
If in your application, you have completed interaction with the RTSP server, close the connection after you have read the response.