Common Lisp中的WebSocket客户端与usocket库

时间:2014-09-01 14:51:16

标签: websocket lisp common-lisp usocket

我尝试升级协议,从HTTP 1.1切换到WebSockets。我试过使用usocket。到目前为止我的代码如下(并以GitHub gist形式提供)。握手读取后,函数返回NILunexpected EOF错误。

;; Define parameter sock for usocket stream
;; echo.websocket.org is a site for testing websockets
(defparameter sock (usocket:socket-connect "echo.websocket.org" 80))

;; Output confirms WebSocket protocol handshake as this implemented in browsers 
(format (usocket:socket-stream sock) "~A~%~A~%~A~%~A~%~A~A~%~A~%~A~%~%" 
        "GET /?encoding=text HTTP/1.1"
        "Connection: Upgrade"
        "Host: echo.websocket.org"
        "Origin: http://www.websocket.org"
        "Sec-WebSocket-Key: " (generate-websocket-key)
        "Sec-WebSocket-Version: 13"
        "Upgrade: websocket")

;; Write output to stream
(force-output (usocket:socket-stream sock))

;; Returns NIL
(do ((line                                                             
      (read-line (usocket:socket-stream sock) nil)                        
      (read-line (usocket:socket-stream sock) nil)))                      
    ((not line))                                                       
  (format t "~A" line))

;; Returns error: unexpected EOF
(read-line (usocket:socket-stream sock))

;; Returns NIL
(listen (usocket:socket-stream sock))

1 个答案:

答案 0 :(得分:8)

~%语句中的

FORMAT在HTTP协议中不可移植。它输出换行符#\newline。换行取决于代码运行的平台:cr(旧Mac,Lisp机器),crlf(Windows)或lf(Unix)。因此,如果您将一个换行符写入流中,则输出取决于您运行的平台(或Lisp系统认为应该执行的操作)。 Windows具有与HTTP相同的行结束约定。

注意:

    Unix系统上的
  • 通常#\newline#\linefeed相同。一个字符。
  • Windows系统上的
  • 常常#\newline与序列#\return #\linefeed相同。两个字符。一些Lisp系统可能会忽略它并使用Unix约定。

HTTP使用crlf。要可靠地编写crlf,您必须编写字符#\return#\linefeed(format stream "~a~a" #\return #\linefeed)

(defun write-crlf (stream)
  (write-char #\return stream)
  (write-char #\linefeed stream))

但是,有些服务器可能会笨拙地读取不符合标准HTTP crlf约定的输入。

打开流时,可能有方法指定行结束约定。但是usocket没有提供这样的功能。

我也会使用finish-output(等待完成)而不是force-output(不等待IO操作的完成)。