I write a websocket though boost, and I receive the message though the client in chrome. When I use ws, it works well, I can receive correct msg. but when I use wss, it works bad, and said could not decode a text frame as UTF 8.
the picture is what's wrong is ssl mode.
c++ send msg code
Json::Value jsonMsg;
jsonMsg["msgType"] = Json::Value("MspServiceStartUp");
jsonMsg["version"] = Json::Value(std::string(MSP_VERSION));
ws_->async_write(boost::asio::buffer((void *) jsonMsg.toStyledString().data(), jsonMsg.toStyledString().size()),
boost::asio::bind_executor(*strand_, [&, sp](boost::system::error_code ec1,
std::size_t bytes_transferred1) {
boost::ignore_unused(bytes_transferred1);
if (ec1) {
LOG_ERR << "async write failed, ec = " << ec1 << ", msg = "
<< ec1.message();
return;
}
// Clear the buffer
buffer_->consume(buffer_->size());
task();
}));
}
js code
var ws=new WebSocket("wss://localhost.com:17801/");
ws.onopen=()=>{console.log('ws open')};
ws.onclose=()=>{console.log('ws close')};
ws.onmessage=(msg)=>{console.log('ws onMessage');console.log(msg)};
Where does this odd character come from? What is the problem? How to fix this ?
The problem is with sending data. async_write()
ends immediately, it doesn't make a copy of data buffer, you have to ensure that data passed into boost::asio::buffer
lives until the full message will be sent.
Even if we added some delay code between async_write
and ending brace {
:
async_write(boost::asio::buffer((void *) jsonMsg.toStyledString().data(), ..));
... some code waiting until write is completed
}
this code will not work also, because toStyledString
returns string
by value.
So temporary string
is created, string::data()
is called, async_write()
ends, and you have dangling pointer inside task initiated by async_write()
.
Quick solution, prolong lifetime of string for example by using smart pointer:
std::shared_ptr<std::string> buf(std::make_shared<std::string>(jsonMsg.toStyledString()));
ws_->async_write(boost::asio::buffer(*buf),
boost::asio::bind_executor(*strand_,
[&, sp, buf](boost::system::error_code ec1,
std::size_t bytes_transferred1)
{
boost::ignore_unused(bytes_transferred1);
if (ec1) {
LOG_ERR << "async write failed, ec = " << ec1 << ", msg = "
<< ec1.message();
return;
}
// Clear the buffer
buffer_->consume(buffer_->size());
task();
}));
pass buf
by boost::asio::buffer(*buf)
, and capture it by value inside lambda: [&,sp,buf]
.