如何使用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函数。

这个想法是这样的:

  1. 在主循环中,将会有一个到receive_board
  2. receive_board将接收成功callback和失败callback作为参数。 (callback是C函数)
  3. 我们将使用Module.ccall从c中调用callbackModule.ccall
  4. 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]); }, }); 

这样,我解决了上述问题。


受到这个答案的启发