enr*_*rey 6 events common-lisp unix-socket node.js
我在node.js的alpha阶段有一个小但CPU重的应用程序,这是一个小游戏.我遇到了性能问题,我需要将其加速至少20倍才能达到测试版.而且由于并行执行会让我走得很远,所以我认为良好的开端是在进程和线程之间共享游戏映射,以便在其上执行并行操作.这在节点中是不可能的,所以我决定在CL(SBCL + Linux)中编写多余的部分并通过unix域套接字连接到它.
计划是:
[players] <-> (node.js front server) <-> (SBCL performing game ticks)
Run Code Online (Sandbox Code Playgroud)
关键是,我需要在类似于socket.io的事情中在node.js和SBCL之间传递快速消息.
这是什么不起作用(你可以跳过这部分)
在节点方面,我不能使用普通的socket.io,因为它不支持Unix域套接字,但是net模块确实如此,所以我至少可以做socket.write('raw data')- 现在好于什么.
在CL方面,我试图运行woo web服务器(它支持本地套接字),我可以从节点连接到它并传递原始数据,但是涉及所有不必要的HTTP部分,而且woo总是作为服务器运行; 它在等待GET / HTTP/1.1 .....我没有找到一种方法来首先从woo实际发起消息.此外,它完全没有文档和未注释,并涉及到很多对C库的FF调用,我对此并不熟悉.
所以我经历了几个没有编译的CL网络服务器,不支持unix套接字,被放弃或未记录,最终转移到普通的sb-bsd-socket,最后转移到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))))
Run Code Online (Sandbox Code Playgroud)
而且我正在
#<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}>)
Run Code Online (Sandbox Code Playgroud)
我不知道我是否应该首先在该套接字上调用accept-connection或listen-to之类的东西.我尝试过的都导致了错误.另外,如果我[RETRY-SYSCALL]在repl中,错误消失了大约10秒但是又回来了.在这个时候,节点仍然无法连接.
这似乎比我想象的要复杂得多.我已经在iolib上独自完成了大约6个小时的工作,我甚至没有开始解析消息,学习如何从它们创建事件,在JSON和s-exps等之间进行转换.
我的问题是:
我接近于抛弃CL的想法,并使用内存mongo之类的东西来代替几个节点进程(...实际上听起来不是很快)但是我喜欢lisp,有点像lparallel这样的东西会很棒后端.我从昨天早上起就没有动过一英寸,我只是无法弄清楚libs.也许我应该学习clojure.
PS:我通常不会要求"给我写代码",但如果有一些好的灵魂,我会非常感激,即使是伪代码.
PPS:也欢迎任何完全不同的方法.请大声说出来:)
谢谢阅读!
如果我正确理解您的问题,您需要在Common Lisp中建立一个服务器.让我重用我之前使用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*)))))
Run Code Online (Sandbox Code Playgroud)
所以最后我想通了...
(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...
)
Run Code Online (Sandbox Code Playgroud)
我切换到后: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;
}
});
});
Run Code Online (Sandbox Code Playgroud)
所以这是可行的,以防其他人有一些类似的将 lisp 和 Node 一起使用的鸡鸡想法。