[racket] How to wait for tcp-accpt-evt unless the listener is or has been closed?

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Thu Sep 13 14:50:52 EDT 2012

My first thought was

 * We should add `tcp-listener-closed?'.

 * The documentation should clarify that a listener becomes ready
   (e.g., `sync' on a listener would return) when the listener is
   closed as well as when it is ready to accept.

 * You could combine a `sync' and a `tcp-listener-closed?' to wait
   until either a connection is ready to accept or the listener is
   closed.

But, of course, there would be a race condition between finding out
that the listener is ready to accept closing the connection on another
thread. Avoiding that race condition requires something more like an
option on `tcp-accept-evt' that determines its behavior (instead of
raising an exception) for a closed listener.


A simpler possibility is to use a custodian that manages both the
listener and the thread. Then, `custodian-shutdown-all' cleanly stops
them both. I recommend that approach, unless you need to make sure that
`receive-file' isn't interrupted.


At Thu, 13 Sep 2012 19:17:55 +0100, Erich Rast wrote:
> Hi all,
> 
> I have a question about tcp-listener. I've implemented a simple
> filetransfer protocol whose main listener loop is this:
> 
> (define (start-listen local-port save-path from-ip progress-proc final-proc
>                       [timeout 60.0] [file-table (make-hash)])
>   (define listener (tcp-listen local-port 1 #t #f))
>   (thread
>    (lambda ()
>      (progress-proc 'listening save-path 0)
>      (let loop ((in-out-ports (sync/enable-break (tcp-accept-evt listener))))
>        (receive-file (first in-out-ports) (second in-out-ports) 
>           save-path progress-proc final-proc file-table timeout)
>        (loop (sync/enable-break (tcp-accept-evt listener))))))
>   listener)
> 
> In my tests, after transfering a file I call (just for fun) stop-listen:
> 
> (define (stop-listen listener)
>   (tcp-close listener))
> 
> and the result is an exception. The problem is, how do I end the loop in the 
> above thread when the listener is closed? Obviously,
> 
> (when (port-closed? (first in-out-ports))
>   (loop (sync/enable-break (tcp-accept-evt listener))))
> 
> does not have the desired effect, because sync/enable-break is already 
> waiting, so when the port is closed tcp-accept-evt correctly raises a network 
> exception. Basically, I need a synchronizable event that yields #f if the 
> listener is closed, the opened ports otherwise. But how? There is not even a 
> tcp-listener-closed? method.
> 
> Any suggestions?
> 
> Best,
> 
> Erich
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users

Posted on the users mailing list.