[racket] flush is not enough, a list is needed

From: Laurent (laurent.orseau at gmail.com)
Date: Fri Nov 2 14:29:20 EDT 2012

Hi,

In a small Racket client/server over tcp, the client sends expressions that
the server evaluates and returns the result to the client, in a loop.
The tcp ports are flushed after each send, but it is still hanging, unless
I wrap the sent values in lists, which is a bit surprising.
So it looks like the buffer won't flush if it's not a list.
Is that a bug (maybe related to
http://bugs.racket-lang.org/query/?cmd=view&pr=12640 , but maybe not) or is
it me?
I can live with it though.

Client:
#lang racket/base

(require racket/tcp)

(printf "Trying to connect to server... ")
(define-values (in out) (tcp-connect "localhost" 54321))
(printf "Ok.\n")

(dynamic-wind
 void
 (λ()
   (printf "rwind-client> ")(flush-output)
   (define exit? #f)
   (for ([e (in-port read)]
         #:break (or exit? (equal? e '(exit)))
         )
     (printf "Sending: ~a\n" e)
     ; Wrap the output in a list, otherwise it may not be sent/flushed
(bug?)
     (write (list e) out)
     (flush-output out)

     ; receiving from server, unwrap
     (define res (car (read in)))
     (if (eof-object? res)
         (set! exit? #t)
         (begin
           (printf "-> ~a\n" res)

           (printf "rwind-client> ")(flush-output)))
     ))
 (λ()
   (printf "Closing connection.\n")
   (close-input-port in)
   (close-output-port out)))


Server:
#lang racket/base

(require racket/tcp)

(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))

(let () ; does this protect the listener from being visible to the
namespace?
  (define listener (tcp-listen 54321))

  (dynamic-wind
   void
   (λ()
     ;; Blocking
     (let accept-loop ()
       (printf "Waiting for client... ")(flush-output)
       (define-values (in out) (tcp-accept listener))
       (printf "Client is connected.\n")

       (dynamic-wind
        void
        (λ()
          (for ([e (in-port read in)]
                #:break (equal? e '(exit))
                )
            (printf "Received ~a\n" e) ;(flush-output)
            (define res
              ; if it fails, simply return the message
              (with-handlers ([exn:fail? (λ(e)(exn-message e))])
                ; unwrap
                (eval (car e) ns)))
            (printf "Sending value: ~a ... " res) (flush-output)
            ; I need to wrap the output in a list, otherwise it may not be
sent/flushed! (bug?)
            (write (list res) out)  (flush-output out)
            (printf "Ok.\n")
            ))
        (λ()
          (printf "Closing connection.\n")
          (close-input-port in)
          (close-output-port out)
          ;(accept-loop) ; uncomment this to not close the listener when
the client disconnects
          ))))
   ; out
   (λ()(tcp-close listener))))



Also, unrelated to the problem above, I want to close everything correctly
when a problem occurs, but it seems that dynamic wind does not do that in
case of a break (e.g., if the exn handler is removed, an invalid operation
will raise an exception, but the ports will not be closed). I may be
misunderstanding what dynamic-wind does.
What would be the "right" way to do things here?


Thanks,
Laurent
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20121102/d067d561/attachment.html>

Posted on the users mailing list.