1

I am trying to get a python program and Allegro Common Lisp program to communicate over sockets. For now, I am trying to set up a Lisp server that listens for connections, get a python client to connect to the server, and then send a simple message from the client to the server. The Lisp server looks as follows:

(let ((socket (socket:make-socket :connect :passive
                              :type :stream
                              :address-family :internet
                              :local-port 45676)))
  (format t "opened up socket ~A for connections~%" socket)

  ;; now wait for connections and accept
  (let ((client (socket:accept-connection socket 
                                      :wait t)))
    (when client
      ;; we've got a new connection from client
      (format t "got a new connection from ~A~%" client)

      ;; now wait for data from client
      (loop until (listen client) do
        (format t "first character seen is ~A~%" (peek-char t client))
        (let ((data (read-line client)))
          (format t "data received: ~A~%" data))))))

The python client looks as follows:

import socket
import time
s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
s.connect (('', 45676))
time.sleep (1) # works if uncommented, does not work if commented
s.sendall ("(list A B)")
s.close ()

Since I want to have multiple messages pass over this stream, I listen for incoming data on the server side and then echo it. However, I noticed a problem when I ran this with the sleep command commented. The output simply looked like this:

opened up socket #<MULTIVALENT stream socket waiting for connection
                   at */45676 @ #x207b0cd2> for connections
got a new connection from #<MULTIVALENT stream socket connected from
                            localhost/45676 to localhost/60582 @
                            #x207b34f2>

In other words, it did not actually echo the data (in my case, "(list A B)"). If I uncommented the sleep command (to introduce some delay between the connection initiation and sending of the data), the output looked like this:

opened up socket #<MULTIVALENT stream socket waiting for connection
                   at */45676 @ #x207b0bea> for connections
got a new connection from #<MULTIVALENT stream socket connected from
                            localhost/45676 to localhost/60572 @
                            #x207b340a>
data received: (list A B)

I'm not sure why this is the case. Does anyone have a solution for this? Is it a bad idea to reuse the same socket connection for multiple exchanges of data? If I remove the entire loop macro call (and thus make it a one-time exchange) the data is received without any problems and is echoed properly

EDIT 1: The last statement is true even with the sleep command commented.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
user114167
  • 63
  • 4
  • Why do you put `until (listen client)` there? – Vsevolod Dyomkin Nov 26 '13 at 20:14
  • As I mentioned, I want to do this data exchange multiple times. So its inside a `loop` macro. However after the first exchange, if there is no data on the stream when it attempts the second `read-line`, it throws an `eof stream` error. So the `until (listen client)` is there to make sure to call the `read-line` only after there is data in the socket. – user114167 Nov 26 '13 at 20:21
  • you can use optional arguments to `read-line`. The usual idiom is this: `for line = (read-line client nil) while line` – Vsevolod Dyomkin Nov 26 '13 at 20:23
  • I'm not sure I understand. This seems like it'll read the first message it gets and echo it correctly. However, before the second message comes in, `read-line` will return `nil` and it exits out of the loop. Isn't that right? If so, then that isn't the functionality I'm trying to achieve. – user114167 Nov 26 '13 at 20:38
  • 1
    what happens is that when the socket is closed and `enf-of-file` is signalled, `read-line` will just return `nil` and the loop will exit (see http://www.lispworks.com/documentation/HyperSpec/Body/f_rd_lin.htm) – Vsevolod Dyomkin Nov 26 '13 at 20:41
  • Ah yes, I was making the mistake of allowing the socket to close before sending the next message. I used the idiom you suggested and it worked perfectly. Thanks! Out of curiosity, any reason why the `listen client` condition behaved the way it did? – user114167 Nov 26 '13 at 21:20

0 Answers0