Как идиоматичнее написать эту функцию на лиспе
Продолжаю щупать скобочки, решил попробовать Common Lisp. Написал простенький tcp сервер, сделал на сокетах (usocket). Выглядит страшненько, но не знаю как написать «правильнее», поэтому решил поинтересоваться у гуру:
(defun create-server (port)
(let ((socket (usocket:socket-listen "127.0.0.1" port :reuse-address t)))
(unwind-protect
(loop
(let ((connection (usocket:socket-accept socket :element-type 'character)))
(progn
(usocket:wait-for-input connection :timeout 10)
(let ((input-data (read-line (usocket:socket-stream connection))))
(when (eq input-data nil) (return))
(format t "Server input is: ~a~%" input-data))
(format (usocket:socket-stream connection) "Pong~%")
(force-output (usocket:socket-stream connection))
(usocket:socket-close connection))))
(progn
(format t "Closing socket.~%")
(usocket:socket-close socket)))))
Первое, что мне кажется не очень правильным это три вложенных let. Вроде поправил на:
(defun create-server (port)
(let ((socket (usocket:socket-listen "127.0.0.1" port :reuse-address t)))
(unwind-protect
(loop
(let* ((connection (usocket:socket-accept socket :element-type 'character))
(stream (usocket:socket-stream connection))
(input-data (read-line stream nil)))
(progn
(usocket:wait-for-input connection :timeout 10)
(when (eq input-data :eof) (return))
(format t "Server input is: ~a~%" input-data)
(format stream "Pong~%")
(force-output stream)
(usocket:socket-close connection))))
(progn
(format t "Closing socket.~%")
(usocket:socket-close socket)))))
Но теперь задержка между отправкой с клиента «Ping» и получением «Pong» стала заметна, возможно проблема в том, что я делаю что-то неправильное с stream и читаю/пишу туда раньше времени. Код клиента
(defun create-client (port)
(let* ((socket (usocket:socket-connect "127.0.0.1" port)))
(unwind-protect
(progn
(format (usocket:socket-stream socket) "Ping~%")
(force-output (usocket:socket-stream socket))
(usocket:wait-for-input socket :timeout 10)
(format t "Input is: ~a~%" (read-line (usocket:socket-stream socket))))
(usocket:socket-close socket))))
Во-вторых, сервер не отрабатывает условие отключения со стороны клиента (пока хочу сделать, чтобы сервер завершал свою работу при отключении клиента). В документации написано:
Reading from a stream which has been closed at the remote end signals an END-OF-FILE condition, meaning that reading from the stream and detecting that condition is the way to do it.
Понимаю только то, что проблема, где-то тут: (when (eq input-data :eof) (return)) – или опять же таки где в моей работе со стримами.
Почему не использую usocket:socket-server? Отвечаю: я так понял, что туда нельзя передать сокет, чтобы ответить что-то клиенту, а же хочу не только читать что мне прислали.
Помогите маленькому лисперу понять что не так. Знаю, что @monk хорошо разбирается в лиспах, из недавнего треда выяснил, что @lovesan в них тоже много понимает и @den73 тоже.