Common lisp 单线程序列读取多用户usocket服务器

Common lisp 单线程序列读取多用户usocket服务器,common-lisp,polling,usocket,Common Lisp,Polling,Usocket,我正在尝试使用usocket库编写一个简单的服务器程序,它将执行一个相对简单的任务,比如,回显数据。我想让它能够对多个客户端执行此操作,而不是在等待任何单个客户端的输入时阻塞单个线程。我发现可以使用等待输入和:timeout 0检查给定套接字是否已准备好输入。但是我很难让读取序列按照我想要的方式工作。如果我给它一个包含50个元素的数组,并且只有5个元素可用,它将等到有50个元素可用时才将它们放入数组中 有没有办法一次(有效地)用一个线程读取块,而不必一直等待输入?或者我真的需要一遍又一遍地调用r

我正在尝试使用usocket库编写一个简单的服务器程序,它将执行一个相对简单的任务,比如,回显数据。我想让它能够对多个客户端执行此操作,而不是在等待任何单个客户端的输入时阻塞单个线程。我发现可以使用
等待输入
:timeout 0
检查给定套接字是否已准备好输入。但是我很难让
读取序列
按照我想要的方式工作。如果我给它一个包含50个元素的数组,并且只有5个元素可用,它将等到有50个元素可用时才将它们放入数组中

有没有办法一次(有效地)用一个线程读取块,而不必一直等待输入?或者我真的需要一遍又一遍地调用
readbyte
,直到我得到所有东西吗

如果有一些与
读取序列
等效的函数只能读取当时可用的数据,或者有一些函数可以告诉我有多少个元素可以读取,这样我就可以适当地调整数组的大小,那么这个问题就可以避免。但这两个我都不知道


更新:我特别寻找不需要读取字符的二进制解决方案,因此涉及
读取字符无挂起
侦听
等的解决方案不会有多大帮助,除非它们有一个二进制等价物。我不想使用字符,因为某些字符编码(如UTF-8)可能具有无效的字节序列,而没有字符表示,我希望能够处理任何字节序列。我特别寻找的解决方案不需要一次读取一个字节,或者确认不存在这样的解决方案(在标准中),在这种情况下,我想听听最方便的库,它可以提供实现这一点所需的最低限度。不仅仅是一次读取一个字节不是最快的方式,它还需要我编写的任何函数以非阻塞的方式来执行,为每个字节使用
usocket
等待输入
函数(因为
侦听
不适用于字节流),这需要函数了解套接字,并且我必须编写一个过度特定的
读取所有字节的
函数,该函数不能处理(比如)文件流。这是可能的,但我希望有一个更通用的方法。

我尝试了rosetta code中的一个代码,一个示例usocket echo服务器,这个函数的诀窍是创建您自己的读取函数。在本例中,read all and wait for:eof,我使用telnet对其进行了测试,结果表明:

代码:

在lisp中初始化:

CL-USER> (in-package :echo)
#<PACKAGE "ECHO">
ECHO> (echo-server 12321)
Got message...
CL-USER>(包中:echo)
#
ECHO>(ECHO服务器12321)
收到消息。。。
使用telnet进行测试:

╭─toni@Antonios-MBP  ~ ‹ruby-2.2.3@laguna› ‹1.7› ‹SBCL 1.3.0›
╰─$ telnet 127.0.0.1 12321
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello, TCP                       #<= Press enter
You said: Hello, TCP
Connection closed by foreign host.
╭─toni@Antonios-MBP~èruby-2.2。3@laguna››1.7››SBCL 1.3.0›
╰─$ telnet 127.0.0.1 12321
正在尝试127.0.0.1。。。
已连接到本地主机。
转义字符为“^]”。

你好,我也很难对付这个

我在项目中使用的一个不可移植的选项是SBCL的默认实现,我正在使用SBCL

使用缓冲区:

(defparameter buf-in (make-array 1024 :element-type '(unsigned-byte 8)))
...
;; suppose variable new-client is your usocket object
(setf my-out (multiple-value-list (sb-bsd-sockets:socket-receive
                     (usocket:socket new-client) bufin nil)))
输出将包含:

(Your buffer, length, address of peer who sent it)

有关SBCL套接字实现的更多信息,请参见更新:意识到这实际上在clisp上不起作用-仅在SBCL上进行了测试,其中(侦听)似乎至少对网络流起到了“您可能认为的”作用。因此,这不是一个可移植的解决方案。。除非替换下面循环中的“(listen)”以使用某种形式的#+功能

因为listen不能处理字节流

(listen)在sbcl上的字节流中工作得非常好。这就解开了戈迪翁的结,让人可以轻松地写下以下内容:

(defun read-sequence-no-hang (seq stream start end)
  (loop
     for i from start below end
     for num-bytes-read = 0 then (1+ num-bytes-read)
     while (listen stream)
     do (setf (elt seq i) (read-byte stream))
     finally (return num-bytes-read)))

不幸的是,这需要以字符序列的形式获取数据。假设我的实现使用UTF-8编码,很有可能到达某些没有字符表示的字节序列。出于某种原因,据我所知,该标准不包括
读取字节无挂起
。我将更新这个问题,以明确我正在寻找一个二进制解决方案。
(defun read-sequence-no-hang (seq stream start end)
  (loop
     for i from start below end
     for num-bytes-read = 0 then (1+ num-bytes-read)
     while (listen stream)
     do (setf (elt seq i) (read-byte stream))
     finally (return num-bytes-read)))