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