Janus Gowda
Janus Gowda

Reputation: 305

Bidirectional socket in List

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.

Upvotes: 0

Views: 298

Answers (1)

Svante
Svante

Reputation: 51501

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.

Upvotes: 1

Related Questions