2016-06-15 6 views
5

node.jsのアルファステージではCPUの重いアプリケーションがありますが、小さなゲームです。私はパフォーマンスの問題を抱えており、ベータ版になるには少なくとも20分の1のスピードアップが必要です。そして並列実行は私を非常に遠くにさせてしまうので、私は、並列処理を実行するプロセスまたはスレッド間でゲームマップを共有するのがよいと判断しました。これはノードでは不可能なので、私は肉体的な部分をCL(SBCL + Linux)に書いて、unixドメインソケットを通してそれに接続することに決めました。Node.jsをクライアントとしてCommon Lispサーバに接続します

計画は次のとおりです。

[players] <-> (node.js front server) <-> (SBCL performing game ticks) 

ポイントは、私はsocket.ioに似た問題でのNode.jsとSBCL間の高速メッセージを渡す必要があります。ここで


は、ノード側

(あなたはこの部分をスキップすることができます)動作しませんでした何で、それはUnixのドメインソケットをサポートしていないので、私は、プレーンsocket.ioを使用することはできません、しかし、netモジュールはそうしていますので、少なくとも私はsocket.write('raw data')を行うことができます。

CL側では、woo Webサーバー(ローカルソケットをサポート)を実行しようとしましたが、ノードから接続して生データを渡すことができますが、不要なHTTPパーツがすべて含まれています。サーバ;それはGET/HTTP/1.1 ....を待っています。私は実際に最初からメッセージを開始する方法を見つけませんでした。また、完全にドキュメント化されておらず、コメントもなく、Cライブラリに多くのFFコールが含まれています。

私は、コンパイルしなかったCL Webサーバー、UNIXソケットをサポートしていなかった、放棄された、または文書化されていない、最終的にプレーンなsb-bsd-socketsに移動して最終的にiolibに移動しました。それを理解する。


iolibは有望に見えたが、私はノードからそれに接続することはできません。

私はこれ持っている:

(with-open-socket (socket :address-family :local 
          :type :datagram 
          ;; :connect :passive 
          :local-filename "/tmp/socket") 

    (format t "Socket created") 
    ;; (listen-on socket) 
    ;; (bind-address socket (make-address "/tmp/socket")) 
    (loop 
    (let ((msg (receive-from socket :size 20))) 
     (format t msg))))  

をし、私は接続を受け入れるか聞く-にその上のようなものを呼び出す必要がある場合、私は知らない

#<Syscall "recvfrom" signalled error EWOULDBLOCK(11) "Resource temporarily unavailable" FD=6> 
    [Condition of type IOLIB/SYSCALLS:EWOULDBLOCK] 

Restarts: 
0: [IGNORE-SYSCALL-ERROR] Ignore this socket condition 
1: [RETRY-SYSCALL] Try to receive data again 
2: [RETRY] Retry SLIME interactive evaluation request. 
3: [*ABORT] Return to SLIME's top level. 
4: [ABORT] abort thread (#<THREAD "worker" RUNNING {10055169A3}>) 

を取得しています最初にソケット。私が試みたすべてがエラーに終わった。また、replでI [RETRY-SYSCALL]とすると、エラーは約10秒間消えますが、戻ってきます。この時点では、ノードはまだ接続できません。

これは私が思ったよりも複雑に思えます。 ..私はすでに一人でiolibに〜の仕事の6時間を失ってしまったし、私もJSONとs-EXPSなどの間で変換し、メッセージを解析し、それらのイベントを作成する方法を学んで起動しませんでした


私の質問はです:

  • そのノードのネットが接続できるように、私はiolibにこの接続を設定するのですか?
  • 私が選択できると仮定して、どのタイプの接続がイベント/メッセージを送るのに最適でしょうか? (データグラム/ストリーム)
  • 私は試していないいくつかの作業ツールがありますか?
  • また、iolib以外にも、おそらくよりハイレベルな/よく書かれている他のライブラリがありますか?
  • このパフォーマンス/並行性の問題に対して、より良い/より簡単な/より高速なアプローチがありますか?
  • 他のアイデア?

私はCLのアイデアを捨てると(..itは本当に速い鳴らない)の代わりに、いくつかのノードのプロセスと、インメモリモンゴようなものを使用に近いが、私はlispのが大好きバックエンドにlparallelのようなものを置くことは素晴らしいことです。私はちょうど昨日の朝から1インチ移動していない、私はlibsを把握することはできません。おそらく私は代わりにクロージャを学ぶべきです。

PS:私は通常 "write me teh code"を要求しませんが、もし良い魂があれば、擬似コードでさえ本当に感謝します。

PPS:根本的に異なるアプローチも歓迎します。してください、あなたの心を話してください:)

読んでいただきありがとうございます!

+2

この質問には多くの質問があり、Lispに関連するものもあれば、より一般的な(TCP対UDPを選ぶ)ものが多すぎます。一方、あなたの質問は面白いです。必要に応じて、次回より集中的な質問を投稿するのをためらってください。非同期通信(cl-async)、JSON(cl-json、yason)などのライブラリは十分に安定しています。それぞれの問題を別々に別々に取り組む方が良いかもしれません。がんばろう。 – coredump

答えて

2

だから、最後に、私は:type :streamに切り替え、ほとんどの問題は消えた...

(with-open-socket (socket :address-family :local 
          :type :stream 
          :connect :passive 
          :local-filename "/tmp/node-sbcl.sock") 

    (log-message :info "Waiting for client...") 
    (setf *client* (accept-connection socket :wait t)) 
    (log-message :info "Accepted client's connection.") 

    ;; ...lunch with *client* + the bits for parsing json and separating messages... 
) 

それを考え出しました。ソケット上でaccept-connectionを呼び出す必要がありますが、listen-toは呼び出さないでください。自分でメッセージを分ける方法を書かなければならなかったが、思ったよりもはるかに簡単だった。何らかの理由で:type :datagramがうまく動作しなかったため、なぜか分かりません。

とノード内:

var JsonSocket = require('json-socket'); 
var net = require('net'); 
var sbcl = new JsonSocket(net.Socket()); 


sbcl.connect("/tmp/node-sbcl.sock"); 
sbcl.on('connect', function(){ 
    console.log('Connected to SBCL, YAY!'); 

    console.log('Sending hi!'); 

    sbcl.sendMessage({'cmd': "heyThere"}); 

    sbcl.on('message', function(message){ 
     if(!message.cmd) { 
      console.log("We've received msg from SBCL with no CMD!!!'"); 
      return; 
     } 

     switch(message.cmd){ 
     case 'heyNode': console.log('SBCL says hi...'); break; 
     } 
    }); 
}); 

だから、これは場合には他の誰かが一緒にLispとノードを使用していくつかの類似した鶏のアイデアを持っている、動作します。

5

問題を正しく理解していれば、Common Lispでサーバーを確立する必要があります。私はUSOCKETを使用するanswer of mine以前を再利用してみましょう:

(use-package :usocket) 

(defun some-server (hostname port)  
    ;; create a server which establishes an event-loop 
    (socket-server hostname ; a string 
       port  ; a number 

       ;; tcp-handler (see API for details) 
       ;; This function is called each time a client connects, 
       ;; and provides a bidirectional stream to communicate with it. 
       ;; The function executes in a context where some useful special 
       ;; variables are bound. 
       ;; The connection is closed automatically on exit. 

       (lambda (stream) 
        ;; format to stream to client 
        (format stream 
          "~D~%" 
          ;; add all elements of the host, 
          ;; a vector of 4 integers 
          (reduce #'+ *remote-host*))))) 
関連する問題