简体   繁体   English

Boost async_read不会给我一个“帧结束”标志

[英]Boost async_read doesn't give me an “end of frame” flag

I'm still working on some kind of client for communication with an IP Camera. 我仍在使用某种客户端与IP摄像机进行通信。 Now I have the following issue: 现在我有以下问题:

I send a request to the camera ( a RTSP DESCRIBE in particular ). 我向相机发送请求(特别是RTSP DESCRIBE )。 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 . 这是答案的标题,后面是所谓的Session Description ,其大小显示在Content-Length字段中。 Actually I don't care much for the Session Description , I'm just interested in the Content-Base field. 实际上,我对Session Description不是很在乎,我只对Content-Base字段感兴趣。 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 . 用于使用来自boost::asioasync_read调用来接收。 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. async_write一样,它只读取更多数据,但是没关系。 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. 现在这也可以正常工作,如果我打印出接收到的字节数,则始终为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. 此部分读取220个字节。 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. 如果我查看来自此调用的控制台输出并将其与帧的实际有效负载进行比较(如Wireshark中所示),我可以看到已收到所有数据。 Now I would actually assume that async_read would set me the eof error. 现在我实际上假设async_read会给我设置eof错误。 But instead the return code of error is success and so it calls async_read again. 但是error的返回代码是success ,因此它再次调用async_read 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. 现在,这与Async HTTP客户端的Boost示例的实现非常相似。 Also it is done the same way in the Example Boost Async HTTP Client . 同样,在示例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. 现在在我看来,它应该对async_read调用没有区别,因为它是HTTP或RTSP - 如果没有更多数据要读取,则帧结束是帧结束。

I'm also aware that according to the boost documentation I am using 我也知道根据我使用的boost文档

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... 但我也尝试了没有CompletionCondition参数的重载函数,它应该在发生错误时返回( EOF !!!) - 但这只是不会回调...

Any suggestions? 有什么建议么? I just don't get what I'm doing wrong... 我只是不明白我在做什么错...

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

  • write an RTSP request 编写RTSP请求
  • to read the response do a boost::asio::async_read_until("\\r\\n\\r\\n") 读取响应,执行boost::asio::async_read_until("\\r\\n\\r\\n")
  • then check for the Content-Length header 然后检查Content-Length标头
  • if content_length > 0 do a boost::asio::transfer_at_least(content_length) 如果content_length> 0进行boost::asio::transfer_at_least(content_length)

Further, why are you expecting an EOF? 此外,您为什么要期待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 . 连接仍处于打开状态:服务器正在等待另一个SETUP或PLAY请求,并且通常直到RTSP TCP连接超时(根据RFC2326的默认值为60秒)后,才会关闭连接。

If in your application, you have completed interaction with the RTSP server, close the connection after you have read the response. 如果您已在应用程序中完成与RTSP服务器的交互,请在阅读响应后关闭连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM