The difference is the state that the TCP port is left in at the protocol level as managed by the OS. For more information, look for "TIME_WAIT" in a TCP reference, such as "TCP/IP Illustrated" by Stevens.
The "More" tutorial avoids the problem by passing #t as the third argument to `tcp-listen`: (define listener (tcp-listen port 5 #t)) The documentation for `tcp-listen` includes a caveat for this way of avoiding the error, but it leaves the details to Stevens. Hope that helps, Matthew At Thu, 23 Feb 2017 09:54:56 -0800, Jordan Johnson wrote: > Hi all, > > The code below is a simple server based on the web server in the “More: > Systems programming in Racket” tutorial. > > This behavior is puzzling me: > I run the server (from the OS X Terminal) and connect a client. > After a wait, the client is disconnected by the timeout (shown in red). > I halt the server with ^C, by triggering the thunk shown in blue. > I start the server again — same way, from the Terminal — and get an “Address > already in use” error. > > This behavior happens consistently. > > What’s perplexing is that if I close the connection from the client side > instead of waiting in step (2) — in which case I understand the bold purple > expression to be closing the connection — I consistently do not get an error. > > I’m puzzled because my current understanding is that the two identical calls > to custodian-shutdown-all should both be shutting down the same threads and > I/O ports that were created under the custodian cust — and that even if this > weren’t the case, the (custodian-shutdown-all main-cust) call should be > cleaning up those same resources (in addition to shutting down the listener), > because cust is subordinate to main-cust. > > So my question is: What difference between the two cases accounts for the > different behavior? > > Thanks, > Jordan > > ;;;;; Example server ;;;;; > > #!/usr/local/racket/bin/racket > #lang racket/base > > (require racket/tcp) > > (define (serve port) > (define main-cust (make-custodian)) > (parameterize ([current-custodian main-cust]) > (define listener (tcp-listen port)) > (define (loop) (accept/handle listener) (loop)) > (thread loop) > ;; Hook to shutdown the server: > (lambda () > (printf "Exiting...~n") > (custodian-shutdown-all main-cust) > (exit 0)))) > > (define (accept/handle l) > (define cust (make-custodian)) > (parameterize ([current-custodian cust]) > (define-values (in out) (tcp-accept l)) > (thread (lambda () > (let loop ([s (read-line in)]) > (unless (eof-object? s) > (fprintf out "Got it.~n") > (flush-output out) > (loop (read-line)))) > (custodian-shutdown-all cust))) > ;; Timeout: > (thread (lambda () (sleep 5) (custodian-shutdown-all cust))))) > > (define stop (serve 9001)) > > (with-handlers ([exn:break? (lambda (e) (stop))]) > (let loop () (sleep 10) (loop))) > > -- > You received this message because you are subscribed to the Google Groups > "Racket Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to racket-users+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.