c++ - 使用 C++ MJPEG 流服务器时缺少 boost::asio 随机标头
问题描述
我想我正面临一个 boost::asio 线程安全问题。让我解释:
语境:
我正在为 Ubuntu 14.04 使用带有 G++ 4.8.4 的 Boost 1.68
我正在编写 C++ 代码来制作 MJPEG 服务器。
这是我的一些代码示例,它的工作原理非常简单:
代码说明
(1) 填写HTTP头
(2) 以 HandleMJPEG 作为回调调用 doWrite
(3) doWrite 以 HandleMJPEG 作为回调调用 async_write
(4) HandleMJPEG:
(4.1) 将 --jpegBoundary 添加到流中
(4.2) 回调 doWrite 再次调用 HandleMJPEG (4.3)
实际代码
void Connection::main()
{
streamInitReply(_reply); // (1)
doWrite(
std::bind(&net::Reply::toBuffers, _reply),
std::bind(&Connection::handleMJPEG, this),
"'MJPEG Stream init header'"); // (2)
}
void streamInitReply(net::Reply& rep)
{
rep.status = net::Reply::Status::ok;
rep.headers.clear();
rep.content.clear();
rep.headers.push_back(net::Header("Connection", "close"));
rep.headers.push_back(net::Header("Max-Age", "0"));
rep.headers.push_back(net::Header("Expires", "0"));
rep.headers.push_back(net::Header("Cache-Control", "no-cache"));
rep.headers.push_back(net::Header("Pragma", "no-cache"));
rep.headers.push_back(
net::Header(
"Content-Type",
(boost::format("multipart/x-mixed-replace; boundary=%1%") % jpegBoundary).str()
)
);
void Connection::handleMJPEG()
{
// Write Boundaries, then write the actual image buffer
// then recall handleMJPEG() to loop and keep writing incoming image
streamBoundariesReply(_reply); // (4.1)
auto self(shared_from_this());
doWrite( // (4.2)
std::bind(&net::Reply::contentToBuffers, _reply),
[this, self](){
imageReply(_server.getImage(), _reply);
doWrite(
std::bind(&net::Reply::toBuffersWithoutStatus, _reply),
std::bind(&Connection::handleMJPEG, this), // 4.3
"'MJPEG Image'"
);
},
"'MJPEG Boundary'"
);
}
void Connection::doWrite(
std::function<std::vector<boost::asio::const_buffer>()> toBuffer,
std::function<void()> callbackOnSuccess,
const std::string& logInfo)
{
auto self(shared_from_this());
boost::asio::async_write(
_socket,
toBuffer(),
boost::asio::bind_executor(strand_, [this, self, logInfo, callbackOnSuccess](const boost::system::error_code& ec, std::size_t)
{
if(ec != boost::system::errc::success)
{
doStop();
}
else
{
callbackOnSuccess(); // (3)
}
}
));
}
TL;博士
问题如下:这段代码在 90% 的时间里都能正常工作。有时,当我想在浏览器(Linux 的 Firefox 66.0.3)上查看流时,会出现“下载”弹出窗口,而不是显示图像。
当我调查这些包时,似乎有一些标题丢失或拼写错误:
1/ 当一切正常时
2/ 当它不正常时
这就是为什么怀疑 boost asio 中存在线程安全问题,但我不知道在哪里查看...
解决方案
你有悬空的参考。你的问题是std::bind
。
简介:当你有一个Foo
具有成员函数的类时bar
:
class Foo {
void bar() {}
};
Foo f;
然后你调用std::bind(&Foo::bar, f)
, std::bind
返回一个函子,它存储f
为 A COPY。
现在让我们返回您的代码:
doWrite(
std::bind(&net::Reply::toBuffers, _reply), // <---- [1]
std::bind(&Connection::handleMJPEG, this),
"'MJPEG Stream init header'");
在 [1] 中,您调用bind
which 创建了存储_reply
. 在doWrite
:
void Connection::doWrite(
std::function<std::vector<boost::asio::const_buffer>()> toBuffer, // [2]
std::function<void()> callbackOnSuccess,
const std::string& logInfo)
{
auto self(shared_from_this());
boost::asio::async_write(
_socket,
toBuffer(), // [3]
boost::asio::bind_executor( ....
...
));
// [4]
}
in [2]toBuffer
是从 . 返回的函子的包装器std::bind
。toBuffer
是局部变量。在第 [3] 行中,您调用toBuffer()
它返回 const-buffers 的副本_reply
- 它不是指原始_reply
!async_write
立即返回 [4]。doWrite
结束并被toBuffer
销毁,而在Boost-lib 机制任务中的某个位置由async_write
works启动,它正在访问从 - 返回的 const-buffers toBuffer
- 在这里你有悬空的参考。
您可以_reply
在调用时通过指针传递bind
- 这样您将引用同一个_reply
实例:
std::bind(&net::Reply::toBuffers, &_reply),
推荐阅读
- python - 对 python 生成器对象感到困惑
- linux - 我部署 python SimpleHTTPServer 并将 html 文件放入其中。但是经过几次请求后,服务器停止响应
- ios - 未调用 WKNavigationDelegate 方法
- c++ - 将 gtest 与 conan 和 cmake 一起使用:'test_properites_mutex_':未声明的标识符
- react-native - 如何在 Expo 和 NativeBase 中调整状态栏
- azure-pipelines - DotNetCoreCLI@2 发布不过滤项目
- python - 如何在不同的类中使用在另一个类中定义的属性?
- r - 根据值“移动窗口”范围和比例对表格进行分类?
- java - 在嵌套 JSON (io.vertx.core.json) 中按键查找值
- c# - VS 代码:OmniSharp 语言服务器正在运行,但没有显示自动建议(C#)