首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >单线程序列读取多用户usocket服务器

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

Stack Overflow用户
提问于 2015-12-07 02:07:23
回答 3查看 602关注 0票数 3

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

是否有任何方法一次读取块(有效)只有一个线程,而不需要不断等待输入?还是我真的必须一次又一次地给read-byte打电话,直到我得到了所有的一切?

如果有一些相当于read-sequence的内容,只读取当时可用的内容,或者有一些函数可以告诉我有多少元素可以读取,那么就可以避免这个问题,这样我就可以适当地调整数组的大小。但我都不知道这两样。

更新:我正在专门寻找不需要读取字符的二进制解决方案,因此涉及read-char-no-hanglisten等的解决方案将不会有很大帮助,除非它们具有二进制等价。我不想使用字符,因为某些字符编码(如UTF-8 )可能具有无效的字节序列,而这些字节序列没有字符表示,而且我希望能够处理任何字节序列。我正在特别寻找不需要一次又一次读取一个字节的解决方案,或者确认不存在这样的解决方案(在标准中),在这种情况下,我想知道最方便的库,它可以提供完成这一任务所必需的最低限度。不仅仅是一次读取一个字节不是最快的方法,它还需要我所写的任何函数以非阻塞的方式对每个字节使用usocketwait-for-input函数(因为listen不适用于字节流),这将要求函数了解套接字,而且我必须编写一个过于特定的read-all-bytes函数,它不能用于文件流。这是可能的,但我希望有一种更通用的方法。

EN

回答 3

Stack Overflow用户

发布于 2015-12-09 07:31:35

我试着使用rosetta代码,一个示例usocket服务器,这个函数的诀窍是创建你自己的读取函数。在本例中,读取所有并等待:eof,我用telnet测试了它,它可以工作:

代码:

代码语言:javascript
复制
;; Sample usocket echo server from Rosetta Code
;; http://rosettacode.org/wiki/Echo_server#Common_Lisp

(ql:quickload (list :usocket))

(defpackage :echo (:use :cl :usocket))

(in-package :echo)

(defun read-all (stream)
  (loop for char = (read-char-no-hang stream nil :eof)
     until (or (null char) (eq char :eof)) collect char into msg
     finally (return (values msg char))))

(defun echo-server (port &optional (log-stream *standard-output*))
  (let ((connections (list (socket-listen "127.0.0.1" port :reuse-address t))))
    (unwind-protect
     (loop (loop for ready in (wait-for-input connections :ready-only t)
          do (if (typep ready 'stream-server-usocket)
             (push (socket-accept ready) connections)
             (let* ((stream (socket-stream ready))
                (msg (concatenate 'string "You said: " (read-all stream))))
               (format log-stream "Got message...~%")
               (write-string msg stream)
               (socket-close ready)
               (setf connections (remove ready connections))))))
      (loop for c in connections do (loop while (socket-close c))))))

在lisp中初始化:

代码语言:javascript
复制
CL-USER> (in-package :echo)
#<PACKAGE "ECHO">
ECHO> (echo-server 12321)
Got message...

用telnet进行测试:

代码语言:javascript
复制
╭─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.

希望这能有所帮助

票数 2
EN

Stack Overflow用户

发布于 2018-03-28 21:29:02

我也和这个做过斗争。

我最后在项目上使用的一个不可移植的选项是我正在使用的SBCL实现的默认选项。

使用缓冲器:

代码语言:javascript
复制
(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)))

产出将包括:

代码语言:javascript
复制
(Your buffer, length, address of peer who sent it)

有关SBCL套接字实现的更多信息是这里

票数 1
EN

Stack Overflow用户

发布于 2019-03-17 03:19:02

更新:意识到这实际上并不适用于clisp测试,仅在SBCL上测试,其中(听)似乎做了“你可能认为”,至少对网络流。因此,这不是一个可移植的解决方案。除非您替换下面循环中的“(侦听)”来使用某种形式的#+特性。

因为listen不适用于字节流

(听)在sbcl上的字节流中运行得非常好。这将解开这里的戈尔迪翁结,使人们能够轻松地写出以下内容:

代码语言:javascript
复制
(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)))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34125365

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档