2016-04-11 1 views
1

Я использую emscripten для переноса проекта C++ в Интернет, а веб-приложение, которое будет взаимодействовать с моим кодом на C++, находится в NodeJs.Как использовать Socket.io с emscripten, используя библиотеку javascript?

Итак, я использую Socket.io на Node.js, и я тоже хочу использовать его с моим кодом на 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 и перезапустил его, а затем результаты появились в консоли браузеров.

+0

'one_iter (') является синхронным, но 'receive_board' кажется асинхронно. – zakki

+0

Должен ли я реализовывать обратные вызовы для обхода асинхронного характера? –

+0

Я так думаю. '3-й параметр 'emscripten_set_main_loop' имеет значение true, one_iter вызывается много раз. – zakki

ответ

2

Кажется, что предложения в комментарии имеют смысл для них.

emscripten_set_main_loop будет имитировать синхронное поведение, однако звонки с JavaScript API являются асинхронными благодаря Socket.io

Так, чтобы решить эту проблему, вместо того, чтобы использовать return заявления и условно выполнить код I want- ли что быть правдой или ложью - я думал об использовании обратных вызовов.

Идея выглядит следующим образом:

  1. В главном цикле, там будет призыв к receive_board.
  2. receive_board будет получать обратный вызов успеха и обратный вызов отказа в качестве параметра. (Обратные вызовы являются функцией C)
  3. Мы будем называть обратные вызовы с помощью c использованием Module.ccall.
  4. Обратные вызовы на самом деле содержат код, который я хотел выполнить условно при получении

Для того, чтобы использовать 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); 
} 
} 

И в яваскрипта стороны

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

+0

Очень умное решение; не думал о динамическом распределении памяти со стороны JS! – Ameo