将Node.js作为客户端连接到Common Lisp服务器

我已经在node.js的alpha阶段有了一个小型的但CPU很重的应用程序,这是一个小游戏。 我遇到了性能问题,我需要加速至less20倍才能达到testing版。 而且由于并行执行会使我走得很远,所以我决定好的开始将是在进程和线程之间共享游戏映射,以便对其执行并行操作。 这在节点上是不可能做到的,所以我决定在CL(SBCL + Linux)中编写肉感的部分,并通过unix域套接字连接到它。

计划是:

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

重点是,我需要在node.js和SBCL之间传递类似于socket.io的快速消息。


这是什么没有工作(你可以跳过这一部分)

在Node端,我不能使用纯socket.io,因为它不支持Unix域套接字,但net模块,所以我可以至less做socket.write('raw data') – 现在好没有比什么都好。

在CL方面,我试图运行woo web服务器(它支持本地套接字),我可以从节点连接到它并传递原始数据,但是所有不必要的HTTP部分都涉及到,并且woo始终作为服务器运行。 它正在等待GET / HTTP/1.1 .... 我没有find一个方法来首先从woo发起一个消息。 另外,它是完全没有logging和未注释的,并且涉及很多对C库的FF调用,这些我都不太熟悉。

所以我又经历了几个没有编译的CL Web服务器,不支持unix套接字,被放弃或者没有logging,最终转移到了纯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}>) 

我不知道是否应该先调用accept-connection或listen-to之类的东西。 我所有的尝试都导致了错误。 另外,如果我在[RETRY-SYSCALL] repl中,错误消失了大约10秒,但又回来了。 在这个时候,节点仍然不能连接。

这似乎变得比我想象的更复杂。 我已经在iolib上独自工作了6个小时,而且我甚至没有开始parsing消息,学习如何从中创build事件,在JSON和s-exps之间转换等等。


我的问题是

  • 我如何在iolib中设置这个连接,使节点的networking可以连接?
  • 假设我可以select,什么types的连接最适合传递事件/消息? (数据报/stream)
  • 有没有一些工作工具,我没有尝试?
  • 另外,还有一些其他的库比iolib可能更高层次/更好的logging?
  • 这个性能/并发性问题有没有更好/更简单/更快的方法?
  • 任何其他的想法?

我接近于抛弃CL的想法,而是用一些像内存中的mongo一样的几个节点进程来代替(虽然它听起来不是很快),但是我喜欢lisp,所以有一些东西像lparallel on后端。 我从昨天早上起就没有动过,我只是无法弄清楚这个库。 也许我应该学习clojure。

PS:我通常不会要求“写我的代码”,但是如果有一个好的灵魂在附近,我真的很感激它,即使是伪代码。

PPS:任何完全不同的方法也是受欢迎的。 请说出你的想法:)

谢谢阅读!

如果我正确理解你的问题,你需要在Common Lisp中build立一个服务器。 让我重复使用USOCKET的以前的答案 :

 (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*))))) 

所以最后我想清楚了

 (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... ) 

我切换到:type :stream和大多数问题消失。 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和节点。