如何使用 javascript 库将 Socket.io 与 emscripten 一起使用?
How to use Socket.io with emscripten using a javascript library?
我正在使用 emscripten 将一个 C++ 项目移植到 Web 中,而要与我的 C++ 代码交互的 Web 应用程序在 NodeJs 上。
所以,我在 Node.js 上使用 Socket.io,我也想将它与我的 C++ 代码一起使用,所以我继续使用 javascript 库,该库使用 socket.io 代码,但是它似乎不起作用。
我写了这个小例子来演示这个案例:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <emscripten.h>
int val = 0;
extern "C"
{
extern void send_board(char* flat_board);
extern bool receive_board(char** _string_dest);
}
void one_iter()
{
#ifdef SEND
char* c = "test";
std::cout << val << std::endl;
if(val%1000 == 0){
send_board(c);
}
val++;
#else
char* c;
if(receive_board(&c)) std::cout << "Received:" << c << std::endl;
#endif
}
int main()
{
emscripten_set_main_loop(one_iter, 0, 1);
return 0;
}
和
mergeInto(LibraryManager.library, {
send_board: function(message) {
socket.on('connect', function(){
socket.emit('game_request_sender_pipeline', {
message: "Hi",
});
});
},
receive_board: function(_string_dest_in_c){
socket.on('connect', function(){
socket.on('game_request_receiver_pipeline' , function (message)
{
var msg = "Other side : " + message.message;
var buffer = Module._malloc(message.message.length + 1);
Module.writeStringToMemory(msg, buffer);
setValue(_string_dest_in_c, buffer, '*');
return true;
});
});
return false;
},
});
我用以下内容编译:
// for the sending test
em++ main.cpp --js-library path_to_js_library.js -o socket.html -DSEND=1
// for the receiving test
em++ main.cpp --js-library path_to_js_library.js -o socket.html
在 Node.Js 服务器代码中,我有:
io.on('connection', function (socket) {
socket.on('game_request_sender_pipeline' , function (message)
{
console.log("game_request_sender_pipeline on.");
socket.broadcast.emit('game_request_receiver_pipeline', {
message: message.message,
});
console.log("game_request_receiver_pipeline emitted.");
});
});
结果很奇怪,直到我认为它不起作用,我取消了 nodejs 服务器并重新启动它,然后结果在浏览器的控制台中弹出。
看来评论中的建议对他们来说很有意义。
emscripten_set_main_loop
将模拟同步行为,但是由于 socket.io
,来自 javascript api 的调用是异步的
所以为了解决这个问题,而不是使用 return
语句并有条件地执行我想要的代码 - 无论是真还是假 - 我想到了使用回调。
想法是这样的:
- 在主循环中,将调用
receive_board
。
receive_board
将接收一个成功回调和一个失败回调作为参数。 (回调是 C 函数)
- 我们将使用
Module.ccall
从 c 调用回调。
- 回调实际上包含我想在收到时有条件地执行的代码
为了使用ccall
,我们必须在函数定义中使用关键字EMSCRIPTEN_KEEPALIVE
,并且为了避免为将要定义的每个回调编写该关键字,我决定只将它用于将调用回调的一个函数。
extern "C"
{
EMSCRIPTEN_KEEPALIVE void callback_invoker(void* fn_ptr, void* fn_arg)
{
// some kind of cast to the original function signature, and to the original fn_arg type
(*fn_ptr)(fn_arg);
}
}
而在javascript这边
mergeInto(LibraryManager.library, {
receive_board: function(_string_dest_in_c, succcess_callback, failure_callback, s_cb_arg, f_cb_arg){
socket.on('connect', function(){
socket.on('game_request_receiver_pipeline' , function (message)
{
var msg = "Other side : " + message.message;
var buffer = Module._malloc(message.message.length + 1);
Module.writeStringToMemory(msg, buffer);
setValue(_string_dest_in_c, buffer, '*');
Module.ccal('callback_invoker', 'void', ['number', 'number'], [success_callback, s_cb_arg]);
return;
});
});
Module.ccal('callback_invoker', 'void', ['number', 'number'], [failure_callback, f_cb_arg]);
},
});
这样我就解决了上述问题
受此启发answer
我正在使用 emscripten 将一个 C++ 项目移植到 Web 中,而要与我的 C++ 代码交互的 Web 应用程序在 NodeJs 上。
所以,我在 Node.js 上使用 Socket.io,我也想将它与我的 C++ 代码一起使用,所以我继续使用 javascript 库,该库使用 socket.io 代码,但是它似乎不起作用。
我写了这个小例子来演示这个案例:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <emscripten.h>
int val = 0;
extern "C"
{
extern void send_board(char* flat_board);
extern bool receive_board(char** _string_dest);
}
void one_iter()
{
#ifdef SEND
char* c = "test";
std::cout << val << std::endl;
if(val%1000 == 0){
send_board(c);
}
val++;
#else
char* c;
if(receive_board(&c)) std::cout << "Received:" << c << std::endl;
#endif
}
int main()
{
emscripten_set_main_loop(one_iter, 0, 1);
return 0;
}
和
mergeInto(LibraryManager.library, {
send_board: function(message) {
socket.on('connect', function(){
socket.emit('game_request_sender_pipeline', {
message: "Hi",
});
});
},
receive_board: function(_string_dest_in_c){
socket.on('connect', function(){
socket.on('game_request_receiver_pipeline' , function (message)
{
var msg = "Other side : " + message.message;
var buffer = Module._malloc(message.message.length + 1);
Module.writeStringToMemory(msg, buffer);
setValue(_string_dest_in_c, buffer, '*');
return true;
});
});
return false;
},
});
我用以下内容编译:
// for the sending test
em++ main.cpp --js-library path_to_js_library.js -o socket.html -DSEND=1
// for the receiving test
em++ main.cpp --js-library path_to_js_library.js -o socket.html
在 Node.Js 服务器代码中,我有:
io.on('connection', function (socket) {
socket.on('game_request_sender_pipeline' , function (message)
{
console.log("game_request_sender_pipeline on.");
socket.broadcast.emit('game_request_receiver_pipeline', {
message: message.message,
});
console.log("game_request_receiver_pipeline emitted.");
});
});
结果很奇怪,直到我认为它不起作用,我取消了 nodejs 服务器并重新启动它,然后结果在浏览器的控制台中弹出。
看来评论中的建议对他们来说很有意义。
emscripten_set_main_loop
将模拟同步行为,但是由于 socket.io
所以为了解决这个问题,而不是使用 return
语句并有条件地执行我想要的代码 - 无论是真还是假 - 我想到了使用回调。
想法是这样的:
- 在主循环中,将调用
receive_board
。 receive_board
将接收一个成功回调和一个失败回调作为参数。 (回调是 C 函数)- 我们将使用
Module.ccall
从 c 调用回调。 - 回调实际上包含我想在收到时有条件地执行的代码
为了使用ccall
,我们必须在函数定义中使用关键字EMSCRIPTEN_KEEPALIVE
,并且为了避免为将要定义的每个回调编写该关键字,我决定只将它用于将调用回调的一个函数。
extern "C"
{
EMSCRIPTEN_KEEPALIVE void callback_invoker(void* fn_ptr, void* fn_arg)
{
// some kind of cast to the original function signature, and to the original fn_arg type
(*fn_ptr)(fn_arg);
}
}
而在javascript这边
mergeInto(LibraryManager.library, {
receive_board: function(_string_dest_in_c, succcess_callback, failure_callback, s_cb_arg, f_cb_arg){
socket.on('connect', function(){
socket.on('game_request_receiver_pipeline' , function (message)
{
var msg = "Other side : " + message.message;
var buffer = Module._malloc(message.message.length + 1);
Module.writeStringToMemory(msg, buffer);
setValue(_string_dest_in_c, buffer, '*');
Module.ccal('callback_invoker', 'void', ['number', 'number'], [success_callback, s_cb_arg]);
return;
});
});
Module.ccal('callback_invoker', 'void', ['number', 'number'], [failure_callback, f_cb_arg]);
},
});
这样我就解决了上述问题
受此启发answer