Двунаправленный сокет в списке
Я пытаюсь связаться от сценария Lisp к другой программе, используя сокеты TCP/IP (с sbcl и библиотекой usocket в системе Linux).
Пока я получил этот код:
(require 'asdf)
(require 'usocket)
(defun start-client ()
( usocket:with-client-socket
(socket stream "0.0.0.0" 30000)
(loop for x in '("1~%" "2~%" "3~%" "4~%" "5~%") do
(format stream x)
(force-output stream)
(sleep 1)
;;(format t "~A~%" (read-line stream))
)
)
)
(start-client)
Код работает хорошо, за исключением закомментированной строки:
(format t "~A~%" (read-line stream))
Таким образом, я могу отправлять и получать сообщения 1,2,3 ... из другого сокета (другой программы) и отправлять сообщения из другой программы в lisp. Однако когда я раскомментирую строку для чтения сообщений из lisp, приведенный выше код, кажется, останавливается и ждет вечно.
1 ответ
Трудно сказать, в чем ваша проблема, не зная сервера. Может быть, это никогда не заканчивает линию?
Вот небольшая демонстрация, использующая потоки для изоляции клиента и сервера:
(in-package #:cl-user)
(eval-when (:compile-toplevel :load-toplevel :execute)
(ql:quickload '("usocket" "bordeaux-threads")))
(defpackage #:usocket-demo
(:use #:cl))
(in-package #:usocket-demo)
(defun serve (port)
"Starts a socket server to answer a single request."
(usocket:with-socket-listener (server-socket "0.0.0.0" port
:reuse-address t)
(let* ((stream-socket (usocket:socket-accept server-socket))
(server-stream (usocket:socket-stream stream-socket))
(request (read-line server-stream))) ; read
(format t "S> serving…~%")
(format server-stream "Hello, ~a!~%" request) ; write
(finish-output server-stream))))
(defun cly (port)
"Makes a single request to a server and prints the answer."
(usocket:with-client-socket (client-socket client-stream "0.0.0.0" port)
(format client-stream "Issa me!~%") ; write
(finish-output client-stream)
(let ((response (read-line client-stream))) ; read
(format t "C> I got a response: ~a~%" response))))
(defun run-demo ()
(let ((bt:*default-special-bindings*
`((*standard-output* . ,*standard-output*))))
(bt:make-thread (lambda ()
(serve 13575))
:name "Server")
(bt:make-thread (lambda ()
(cly 13575))
:name "Client")
(values)))
Привязка bt:*default-special-bindings
необходимо, чтобы потоки видели один и тот же поток вывода для демонстрационных сообщений.
Как видите, и клиент, и сервер имеют поток, из которого они могут читать и записывать.