4

我正在尝试升级协议,从 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))
4

1 回答 1

9

~%对于 HTTP 协议而言,in a FORMATstatement 是不可移植的。它输出换行符#\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 操作完成)。

于 2014-09-01T17:53:46.477 回答