如何使用 Socket.io 和 emscripten 使用 javascript 库?

Posted

技术标签:

【中文标题】如何使用 Socket.io 和 emscripten 使用 javascript 库?【英文标题】:How to use Socket.io with emscripten using a javascript library? 【发布时间】:2016-04-11 22:23:25 【问题描述】:

我正在使用 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 服务器并重新启动它,然后结果在浏览器的控制台中弹出。

【问题讨论】:

one_iter() 是同步的,但 receive_board 似乎是异步的。 我应该实现回调来解决它的异步性质吗? 我是这么认为的。emscripten_set_main_loop的第三个参数是真的,one_iter被调用了很多次。 是的,因为真正的问题发生在图形游戏中,我需要最后一个 arg 为真以模拟无限循环,如果我错了,请纠正我 【参考方案1】:

评论中的建议似乎对他们有意义。

emscripten_set_main_loop 将模拟同步行为,但是由于 socket.io,来自 javascript api 的调用是异步的

所以为了解决这个问题,而不是使用return 语句并有条件地执行我想要的代码——无论是真还是假——我想到了使用回调。

这个想法是这样的:

    在主循环中,将调用receive_boardreceive_board 将接收成功回调和失败回调作为参数。 (回调是 C 函数) 我们将使用 Module.ccall 从 c 调用回调。 回调实际上包含我想在收到时有条件地执行的代码

为了使用ccall,我们必须在函数定义中使用关键字EMSCRIPTEN_KEEPALIVE,为了避免为每个要定义的回调编写该关键字,我决定只使用它对于将调用回调的 one 函数。

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

【讨论】:

非常聪明的解决方案;没想到从JS端动态分配内存!

以上是关于如何使用 Socket.io 和 emscripten 使用 javascript 库?的主要内容,如果未能解决你的问题,请参考以下文章

如何在前端获取 socket.on 函数?事件被触发和处理。我正在使用 socket.io、NodeJS 服务器和 Redis.io

如何使用 Express、AngularJS、Socket.io 广播和获取通知?

如何在android上使用socket.io和后台服务?

如何将 Asterisk ARI 与 socket.io 和 Node.js 一起使用

如何使用 Angular 和 Jasmine 模拟 socket.io

如何在 express 和 socket.io 中使用护照?