Currently i am writing a C++ Websocket Client Library which get wrapped in a C# Library.
I am using Boost Beast for the websocket connection.
Now i am at the point that i start a async_read when the handshake is completed so the websocket dont disconnect.
The Problem is the io_content blocks the thread so the C# program stops excecuting until the async_read gets a timeout and the io_content returns. But i want that the C# program keep executing.
I tried to execute the connect function in a thread, but there's the problem, that the next function that the C# program calls is a write operation and it crashes, because the connect function is still connecting...
library.cpp:
void OpenConnection(char* id)
{
std::cout << "Opening new connection..." << std::endl;
std::shared_ptr<Session> session = std::make_shared<Session>();
session->connect();
sessions.emplace(std::string(id), std::move(session));
}
session.cpp:
void Session::connect()
{
resolver.async_resolve(
"websocket_uri",
"443",
beast::bind_front_handler(
&Session::on_resolve,
shared_from_this()));
ioc.run();
}
The on_resolve,on_connect,on_handshake... are the same as here: https://www.boost.org/doc/libs/1_70_0/libs/beast/example/websocket/client/async-ssl/websocket_client_async_ssl.cpp
Unless the on_handshake function:
void Session::on_handshake(beast::error_code ec)
{
if (ec)
return fail(ec, "handshake");
ws.async_read(buffer, beast::bind_front_handler(&Session::on_read, shared_from_this()));
}
And the on_read function:
void Session::on_read(beast::error_code ec, std::size_t bytes_transfered)
{
boost::ignore_unused(bytes_transfered);
if (ec)
return fail(ec, "read");
std::cout << "Got message" << std::endl;
onMessage(Message::parseMessage(beast::buffers_to_string(buffer.data())));
ws.async_read(buffer, beast::bind_front_handler(&Session::on_read, shared_from_this()));
}
And the on_write function:
void Session::on_write(beast::error_code ec, std::size_t bytes_transfered)
{
boost::ignore_unused(bytes_transfered);
if (ec)
return fail(ec, "write");
queue.erase(queue.begin());
if (!queue.empty())
{
ws.async_write(net::buffer(queue.front()->toString()), beast::bind_front_handler(&Session::on_write, shared_from_this()));
}
}
C# Program(For testing):
[DllImport(@"/data/cpp_projects/whatsapp_web_library/build/Debug/libWhatsApp_Web_Library.so")]
public static extern void OpenConnection(string id);
[DllImport(@"/data/cpp_projects/whatsapp_web_library/build/Debug/libWhatsApp_Web_Library.so")]
public static extern void CloseConnection(string id);
[DllImport(@"/data/cpp_projects/whatsapp_web_library/build/Debug/libWhatsApp_Web_Library.so")]
public static extern void GenerateQRCode(string id);
static void Main(string[] args)
{
string id = "test";
OpenConnection(id);
GenerateQRCode(id);
}
Now is my question, how can i implement this?
I have been stuck on this problem for 3 days now and am slowly despairing.
Thanks already :)
You need to use async_read_some
instead of async_read
From boost
async_read_some function is used to asynchronously read data from the stream socket. The function call always returns immediately.
The read operation may not read all of the requested number of bytes. Consider using the async_read function if you need to ensure that the requested amount of data is read before the asynchronous operation completes.
Basically a successful call to async_read_some
may read just one byte,
or it may fill the whole buffer, or anywhere in between. The
asio::async_read
function, on the other hand, can be used to ensure that the entire
buffer is filled before the operation completes. The async_write_some
and asio::async_write
functions have the same relationship.
Here is a good example of how to use async_read_some