0

I'm trying to communicate from a Lisp script to another program by using TCP/IP sockets (with sbcl and the usocket library in a Linux system).

So far I got this code:

(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)

The code works well with the exception of the commented line:

(format t "~A~%" (read-line stream))

So I'm able to send and receive the messages 1,2,3 ... from the other socket (another program) and send messages back from the other program to lisp. However, when I uncomment the line to read the messages from lisp, the above code seems to stop and wait forever.

Janus Gowda
  • 295
  • 1
  • 4
  • 17
  • Probably a good time, while you are waiting for answers, to think about formatting your code in a readable way. There is room for improvement. Let us know if you need help - well formatted and indented code makes it easier for your audience to read your code. – Rainer Joswig Sep 10 '18 at 18:28
  • Also a great thing for a question would be a real test case to reproduce. As it is now we can only guess what you do and what the server does. Until you provide such a test case we can reproduce I, sadly, have to vote to close this question, because there is not enough information. – Rainer Joswig Sep 10 '18 at 19:39

1 Answers1

1

It is difficult to tell what your problem is, without knowing the server. Maybe it never terminates the line?

Here is a little demo, using threads to isolate client and server:

(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)))

The binding of bt:*default-special-bindings is necessary so that the threads see the same output stream for the demo messages.

As you see, both client and server have a stream that they can read from and write to.

Svante
  • 50,694
  • 11
  • 78
  • 122