複数のスレッドを使用するようにwebsocket++ エコー サーバーの例を変更しました。
#include <iostream>
#include <boost/thread/thread.hpp>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
// pull out the type of messages sent by our config
typedef server::message_ptr message_ptr;
// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg)
{
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
std::cout << "Echo failed because: " << e << "(" << e.message() << ")" << std::endl;
}
}
int main()
{
// Create a server endpoint
server echo_server;
boost::asio::io_service io_service;
try {
// Initialize Asio
echo_server.init_asio(&io_service);
// Register our message handler
echo_server.set_message_handler(bind(&on_message, &echo_server, ::_1, ::_2));
// Listen on port 9002
echo_server.set_reuse_addr(true);
echo_server.listen(9002);
// Start the server accept loop
echo_server.start_accept();
boost::thread_group threadpool;
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
threadpool.join_all();
} catch (websocketpp::exception const& e) {
std::cout << e.what() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
}
多くのメッセージを非同期で送信する 1 つのクライアントを使用して接続します。次に、サーバーが次のようにクラッシュします。
2016-08-31 13:05:44] [info] asio async_read_at_least error: system:125 (Operation canceled)
[2016-08-31 13:05:44] [error] handle_read_frame error: websocketpp.transport:2 (Underlying Transport Error)
terminate called after throwing an instance of 'std::bad_weak_ptr'
what(): bad_weak_ptr
Thread Safety に関する websocket++ マニュアルから判断すると、私が行っていることはスレッドセーフである必要があります。
Asio トランスポートは、エンドポイントに完全なスレッド セーフを提供します。複数のスレッドが io_service.run() を呼び出している io_service スレッド プールで動作します。
...
すべてのコア トランスポートは、特定の接続のハンドラーがシリアル化されることを保証します。トランスポート ポリシーと同時実行ポリシーがエンドポイントの同時実行をサポートしている場合、connection_hdl を含むものはすべてスレッド セーフにする必要があります。つまり、connection_hdls を他のスレッドに渡し、それらを無期限に保存し、それらをパラメーターとして受け取るエンドポイント メソッドを任意のスレッドからいつでも呼び出すことは安全です。
ここで何が欠けていますか?
私が使用しているクライアントは NodeJS に基づいています。
client.js
var port = 9002;
var times = 10000;
var WebSocket = require("ws");
var ws = new WebSocket("ws://localhost:" + port);
ws.on('open', function open() {
for(var i = 0; i < times; ++i) {
ws.send(i);
}
});
経由で開始:
$ npm install --save ws
$ node client.js