From 68c75d381a92ca4eab34b2e7664bfb2618ad643e Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Tue, 17 Jul 2012 12:07:17 -0400 Subject: [PATCH] Using a thread to (partially) manage the server state --- chat-threadstate.rkt | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 chat-threadstate.rkt diff --git a/chat-threadstate.rkt b/chat-threadstate.rkt new file mode 100644 index 0000000..ba5852c --- /dev/null +++ b/chat-threadstate.rkt @@ -0,0 +1,60 @@ +#lang racket/base + +(require racket/set) +(require racket/match) +(require racket/tcp) +(require racket/port) + +(define (main) + (define listener (tcp-listen 5999 4 #t)) + (let loop () + (define-values (cin cout) (tcp-accept listener)) + (define-values (local-host local-port remote-host remote-port) (tcp-addresses cin #t)) + (thread (connection-handler cin cout (cons remote-host remote-port))) + (loop))) + +(define (connection-handler cin cout connection-id) + (lambda () + (with-handlers ((exn:fail? (lambda (e) + (thread-send active-connection-thread + `(depart ,(current-thread) ,connection-id)) + (raise e)))) + (thread-send active-connection-thread `(arrive ,(current-thread) ,connection-id)) + (let loop () + (sync (wrap-evt (read-bytes-line-evt cin 'any) + (lambda (line) + (cond [(eof-object? line) 'done] + [else + (for ([c active-connections]) + (thread-send (car c) `(says ,connection-id ,line))) + (loop)]))) + (wrap-evt (thread-receive-evt) + (lambda (dummy) + (write (thread-receive) cout) + (newline cout) + (flush-output cout) + (loop))))) + (thread-send active-connection-thread `(depart ,(current-thread) ,connection-id))))) + +(define active-connections (set)) +(define active-connection-thread + (thread + (lambda () + (let loop () + (match (thread-receive) + [`(arrive ,caller ,connection-id) + (thread-send caller `(you-are ,connection-id)) + (for ([c active-connections]) + (thread-send caller `(arrived ,(cdr c))) + (thread-send (car c) `(arrived ,connection-id))) + (define new-connections (set-add active-connections (cons caller connection-id))) + (set! active-connections new-connections)] + [`(depart ,caller ,connection-id) + (define new-connections (set-remove active-connections (cons caller connection-id))) + (set! active-connections new-connections) + (for ([c active-connections]) (thread-send (car c) `(departed ,connection-id)))]) + (loop))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(main)