Hi Tony,
Thanks for offering your interpretation of the racket reference manual.
Below is my attempt to test whether or not the input port does indeed
become closed when the TCP connection is broken.
The broken TCP connection is provided by combining curl with GNU
coreutils timeout.
I try testing the input port for closedness two different ways. The
default code tests with port-closed-evt. The commented out code tests by
calling port-closed? in a loop. Neither method succeeds in detecting
the broken TCP connection.
Thanks for any help.
Regards,
Jeff Henrikson
#lang racket
;; Tony Garnock-Jones,
https://groups.google.com/g/racket-users/c/H43jr8QuM-4
;; "... if the connection breaks, the ports will be closed as usual. .
. ."
(define (handle-by-event in out k)
; Discard the HTTP request header (up to blank line):
(regexp-match #rx"(\r\n|^)\r\n" in)
(displayln "about to sleep")
(flush-output (current-output-port))
(let ((evt (sync/timeout 10 (port-closed-evt in))))
(if evt
(begin
(displayln "got close evt\n")
(k))
(begin
(displayln "done sleeping")
(flush-output (current-output-port))
(display "HTTP/1.0 200 Okay\r\n" out)
(display "Server: k\r\nContent-Type: text/html\r\n\r\n" out)
(display "<html><body>Hello, world!</body></html>" out)
(k)))))
;; same as handle-by-event but using port-closed? instead of port-closed-evt
(define (handle-by-polling in out k)
(define (iter i)
(when (> i 0)
(printf "closed=~a\n" (port-closed? in))
(sleep 1)
(iter (- i 1))))
; Discard the request header (up to blank line):
(regexp-match #rx"(\r\n|^)\r\n" in)
(displayln "about to sleep")
(flush-output (current-output-port))
(iter 10)
(displayln "done sleeping")
(flush-output (current-output-port))
(display "HTTP/1.0 200 Okay\r\n" out)
(display "Server: k\r\nContent-Type: text/html\r\n\r\n" out)
(display "<html><body>Hello, world!</body></html>" out)
(k))
(define (accept-and-handle listener)
(define-values (in out) (tcp-accept listener))
;; alternatively: (handle-by-polling in out (lambda ()
(handle-by-event in out (lambda ()
(displayln "handle finished")
))
(close-input-port in)
(close-output-port out))
(define (serve port-no)
(define listener (tcp-listen port-no 5 #t))
(define (loop)
(accept-and-handle listener)
(loop))
(loop))
(serve 8000)
#|
Test with curl and GNU coreutils timeout:
timeout --foreground 3s curl http://127.0.0.1:8000
actual output (handle-by-event version):
about to sleep
done sleeping
handle finished
expected output (handle-by-event version):
about to sleep
got close evt
handle finished
Tested on:
Racket v8.0 cs
on Ubuntu 20.04.4 LTS
|#
Hi Jeff,
You can use `tcp-listen` and `tcp-accept` [0] to accept connections.
Once accepted, the connection appears as a matched pair of ports, one
for input and one for output, and if the connection breaks, the ports
will be closed as usual. In some circumstances, you will get an
exception such as "connection reset" (see `exn:fail:network`). If you
need to reliably distinguish closed-by-peer, all-ok from
closed-by-weird-network-weather, your application protocol has to
handle that, there's nothing TCP can do for you there. HTTP does this
via content-length and/or chunking, for example.
Cheers,
Tony
[0]: https://docs.racket-lang.org/reference/tcp.html
On 6/30/22 11:34 AM, Jeff Henrikson wrote:
Racket users,
How do I accept an inbound TCP connection so that once I am
processing it, if the connection is broken by the client or network,
my program promptly finds out?
Regards,
Jeff Henrikson
--
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.
To view this discussion on the web visit
https://groups.google.com/d/msgid/racket-users/e3445bfa-8d75-bbf5-1900-226a67e71599%40gmail.com.