如何使用emscripten使用JavaScript库Socket.io?
我正在使用emscripten将一个c ++项目移植到web中,并且要与我的C ++代码交互的web应用程序在NodeJs上。
所以,我在Node.js上使用了Socket.io,我也想用它来使用我的c ++代码,所以我使用了一个使用socket.io代码的JavaScript库,但是它似乎不起作用。
我写了这个小例子来演示这个例子:
#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服务器并重新启动,然后结果在浏览器的控制台中popup。
看来评论中的build议对他们有意义。
emscripten_set_main_loop
会模拟一个同步行为,但是来自javascript api的调用是asynchronous的,因为socket.io
因此,为了解决这个问题,我没有使用return
语句,而是有条件地执行我想要的代码 – 无论是true还是false – 我都想用callback函数。
这个想法是这样的:
- 在主循环中,将会有一个到
receive_board
。 -
receive_board
将接收成功callback和失败callback作为参数。 (callback是C函数) - 我们将使用
Module.ccall
从c中调用callbackModule.ccall
。 - callback实际上包含我希望在收到时有条件地执行的代码
为了使用ccall
,我们将必须在函数定义中使用关键字EMSCRIPTEN_KEEPALIVE
,并且为了避免为将要定义的每个callback编写关键字,我决定只将它用于一个将调用的函数callback。
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]); }, });
这样,我解决了上述问题。
受到这个答案的启发