From a93d17e0e65458e8dbadf5d510229b0a9c9e1470 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Wed, 5 Apr 2017 15:30:10 -0400 Subject: Two threads of execution example --- concurrentreadandprint.rkt | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 concurrentreadandprint.rkt diff --git a/concurrentreadandprint.rkt b/concurrentreadandprint.rkt new file mode 100644 index 0000000..2272d97 --- /dev/null +++ b/concurrentreadandprint.rkt @@ -0,0 +1,51 @@ +#lang racket +;; author: Ibrahim Mkusa +;; about: print and read concurrently + +;; reads values continously from stdin and redisplays them +(define (read-loop) + (display (read-line)) + (display "\n") + (read-loop) + ) + +(define input-prompt "input: ") +(define output-prompt "output: ") + +;; prompt for username and bind to a variable username +(display "What's your name?\n") +(define username (read-line)) +(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt +(define fair (make-semaphore 1)) + +;; intelligent read, quits when user types in "quit" +(define (read-loop-i) + (display usernamei) + + (semaphore-wait fair) + (define input (read-line)) + ;; do something over here with input maybe send it out + (cond ((string=? input "quit") (exit))) + (display (string-append output-prompt input "\n")) + (semaphore-post fair) + (read-loop-i) + ) + + +;; print hello world continously +(define (hello-world) + (semaphore-wait fair) + (display "Hello, World!\n") + (semaphore-post fair) + (hello-world)) + +(define t (thread (lambda () + (read-loop-i)))) +(define a (thread (lambda () + (hello-world)))) +;; below doesn't execute +; (sleep 10) +; (kill-thread t) +; (define a (thread (display "hello world!\n"))) +; (display "John: hello soso\n") +; (display "Emmanuel: cumbaya!!!!\n") \ No newline at end of file -- cgit v1.2.3 From 768395102489dab0997ca6b7180c28e51872e665 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Wed, 5 Apr 2017 15:46:50 -0400 Subject: properly kills threads and returns prompt to main --- concurrentreadandprint.rkt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/concurrentreadandprint.rkt b/concurrentreadandprint.rkt index 2272d97..a9a71ed 100644 --- a/concurrentreadandprint.rkt +++ b/concurrentreadandprint.rkt @@ -2,6 +2,10 @@ ;; author: Ibrahim Mkusa ;; about: print and read concurrently +;; create custodian for managing all resources +;; so we can shutdown everything at once +(define guard (make-custodian (current-custodian))) +(current-custodian guard) ;; reads values continously from stdin and redisplays them (define (read-loop) (display (read-line)) @@ -25,7 +29,8 @@ (semaphore-wait fair) (define input (read-line)) ;; do something over here with input maybe send it out - (cond ((string=? input "quit") (exit))) + (cond ((string=? input "quit") (begin (kill-thread a) + (kill-thread t)))) (display (string-append output-prompt input "\n")) (semaphore-post fair) (read-loop-i) @@ -43,6 +48,8 @@ (read-loop-i)))) (define a (thread (lambda () (hello-world)))) + +(thread-wait t) ;; returns prompt back to drracket ;; below doesn't execute ; (sleep 10) ; (kill-thread t) -- cgit v1.2.3 From 91c611e2afbef6491f16be2fca4bc42fe891b501 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Wed, 5 Apr 2017 16:01:17 -0400 Subject: fixed an issue with username not appearing nicely --- concurrentreadandprint.rkt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/concurrentreadandprint.rkt b/concurrentreadandprint.rkt index a9a71ed..7e7a78b 100644 --- a/concurrentreadandprint.rkt +++ b/concurrentreadandprint.rkt @@ -1,4 +1,6 @@ #lang racket +(require math/base) ;; for random number generation + ;; author: Ibrahim Mkusa ;; about: print and read concurrently @@ -24,11 +26,15 @@ ;; intelligent read, quits when user types in "quit" (define (read-loop-i) - (display usernamei) + (semaphore-wait fair) + (display usernamei) (define input (read-line)) ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh (cond ((string=? input "quit") (begin (kill-thread a) (kill-thread t)))) (display (string-append output-prompt input "\n")) @@ -38,9 +44,13 @@ ;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port (define (hello-world) + (sleep (random-integer 0 60)) ;; sleep between 0 and 60 seconds to simulate coms + ;; with server (semaphore-wait fair) - (display "Hello, World!\n") + (display "\nHello, World!\n") (semaphore-post fair) (hello-world)) -- cgit v1.2.3 From 819c6a9f7479a743d16b66dbfda31817b1502bd4 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Wed, 5 Apr 2017 16:22:51 -0400 Subject: Added simulation for multiple users --- concurrentreadandprint.rkt | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/concurrentreadandprint.rkt b/concurrentreadandprint.rkt index 7e7a78b..709dd18 100644 --- a/concurrentreadandprint.rkt +++ b/concurrentreadandprint.rkt @@ -1,8 +1,10 @@ #lang racket (require math/base) ;; for random number generation + ;; author: Ibrahim Mkusa ;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely ;; create custodian for managing all resources ;; so we can shutdown everything at once @@ -28,7 +30,7 @@ (define (read-loop-i) - (semaphore-wait fair) + ;(semaphore-wait fair) (display usernamei) (define input (read-line)) ;; do something over here with input maybe send it out @@ -38,7 +40,7 @@ (cond ((string=? input "quit") (begin (kill-thread a) (kill-thread t)))) (display (string-append output-prompt input "\n")) - (semaphore-post fair) + ;(semaphore-post fair) (read-loop-i) ) @@ -47,11 +49,16 @@ ;; "(hello-world)" can be executed as part of background thread ;; that prints in the event there is something in the input port (define (hello-world) - (sleep (random-integer 0 60)) ;; sleep between 0 and 60 seconds to simulate coms + (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms ;; with server - (semaphore-wait fair) - (display "\nHello, World!\n") - (semaphore-post fair) + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + ;; at this time we simulate the input from different users + (define what-to-print (random-integer 0 2)) + (if (= what-to-print 0) + (display "Doug: What's up, up?\n") + (display "Fred: Looking good, good!\n")) + ;(semaphore-post fair) (hello-world)) (define t (thread (lambda () -- cgit v1.2.3 From 56bc37f69d92a37cea8b6f0e3ca1ebbf970397a1 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Wed, 5 Apr 2017 16:39:47 -0400 Subject: I can read and process input iteratively --- concurrentreadandprint.rkt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/concurrentreadandprint.rkt b/concurrentreadandprint.rkt index 709dd18..84882b4 100644 --- a/concurrentreadandprint.rkt +++ b/concurrentreadandprint.rkt @@ -5,11 +5,13 @@ ;; author: Ibrahim Mkusa ;; about: print and read concurrently ;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 ;; create custodian for managing all resources ;; so we can shutdown everything at once -(define guard (make-custodian (current-custodian))) -(current-custodian guard) +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) ;; reads values continously from stdin and redisplays them (define (read-loop) (display (read-line)) -- cgit v1.2.3 From c426214e24893a895aa794f02b2e8728410c0033 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Wed, 5 Apr 2017 16:51:51 -0400 Subject: Lets try communication over tcp on localhost crpovertcp.rkt --- crpovertcp.rkt | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 crpovertcp.rkt diff --git a/crpovertcp.rkt b/crpovertcp.rkt new file mode 100644 index 0000000..84882b4 --- /dev/null +++ b/crpovertcp.rkt @@ -0,0 +1,77 @@ +#lang racket +(require math/base) ;; for random number generation + + +;; author: Ibrahim Mkusa +;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 + +;; create custodian for managing all resources +;; so we can shutdown everything at once +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) +;; reads values continously from stdin and redisplays them +(define (read-loop) + (display (read-line)) + (display "\n") + (read-loop) + ) + +(define input-prompt "input: ") +(define output-prompt "output: ") + +;; prompt for username and bind to a variable username +(display "What's your name?\n") +(define username (read-line)) +(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt +(define fair (make-semaphore 1)) + +;; intelligent read, quits when user types in "quit" +(define (read-loop-i) + + + ;(semaphore-wait fair) + (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (begin (kill-thread a) + (kill-thread t)))) + (display (string-append output-prompt input "\n")) + ;(semaphore-post fair) + (read-loop-i) + ) + + +;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port +(define (hello-world) + (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms + ;; with server + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + ;; at this time we simulate the input from different users + (define what-to-print (random-integer 0 2)) + (if (= what-to-print 0) + (display "Doug: What's up, up?\n") + (display "Fred: Looking good, good!\n")) + ;(semaphore-post fair) + (hello-world)) + +(define t (thread (lambda () + (read-loop-i)))) +(define a (thread (lambda () + (hello-world)))) + +(thread-wait t) ;; returns prompt back to drracket +;; below doesn't execute +; (sleep 10) +; (kill-thread t) +; (define a (thread (display "hello world!\n"))) +; (display "John: hello soso\n") +; (display "Emmanuel: cumbaya!!!!\n") \ No newline at end of file -- cgit v1.2.3 From 1edfa0442c29f5d69e720763ae22b330de2a4388 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Fri, 7 Apr 2017 13:18:20 -0400 Subject: iterative updates --- Makefile | 3 +++ crpovertcp.rkt | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..eda5bbb --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +# Remove idiotic save files +clean: + rm -rf *~ diff --git a/crpovertcp.rkt b/crpovertcp.rkt index 84882b4..7ec3745 100644 --- a/crpovertcp.rkt +++ b/crpovertcp.rkt @@ -1,6 +1,60 @@ #lang racket (require math/base) ;; for random number generation +;; globals +;; must control access via semaphore as listener thread or broadcast thread +;; might need to access it +(define connections '()) + +;; This is a single server communicating directly to the client + +;;;;;;;;;;;;;;;;;;;;;;Server Client communication;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(define (serve in-port out-port) + (let loop [] + (define evt (sync/timeout 2 + (read-line-evt in-port 'any) + (thread-receive-evt))) + (cond + [(not evt) + (displayln "Timed out, exiting") + (tcp-abandon-port in-port) + (tcp-abandon-port out-port)] + [(string? evt) + (fprintf out-port "~a~n" evt) ;; echoes back received string + (flush-output out-port) ;; flushes the buffer + (loop)] ;; iterates again + [else + (printf "Received a message in mailbox: ~a~n" + (thread-receive)) + (loop)]))) + +(define port-num 4322) +(define (start-server) + (define listener (tcp-listen port-num)) + (thread + (lambda () + (let loop () ;; the server now loops continously listening in for connections + (define-values [in-port out-port] (tcp-accept listener)) + ;; lets add this open ports to global list of connections + (semaphore-wait fair) + (append connections (list (list in-port out-port))) + (semaphore-post fair) + (serve in-port out-port) ; could be do the greeting in here + (loop))))) + +(start-server) + +(define client-thread + (thread + (lambda () + (define-values [in-port out-port] (tcp-connect "localhost" port-num)) + + (display "first\nsecond\nthird\n" out-port) + (flush-output out-port) + ; copy-port will block until EOF is read from in-port + (copy-port in-port (current-output-port))))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; author: Ibrahim Mkusa ;; about: print and read concurrently -- cgit v1.2.3 From e0354fd1c24c2a918d433837b727016474c19c0b Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 12:53:03 -0400 Subject: keeping count of input and output ports directly is feasible. Trying a different way. --- crpovertcp.rkt | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 4 deletions(-) diff --git a/crpovertcp.rkt b/crpovertcp.rkt index 7ec3745..de04790 100644 --- a/crpovertcp.rkt +++ b/crpovertcp.rkt @@ -4,8 +4,101 @@ ;; globals ;; must control access via semaphore as listener thread or broadcast thread ;; might need to access it -(define connections '()) - +(define connections '()) ;; maintains a list of open ports +;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) + +;; lets keep thread descriptor values +; + +(define fair (make-semaphore 1)) ;; managing connections above + +(define can-i-broadcast (make-semaphore 1)) + +;; alternative one keep running list of input and output ports directly +;; broadcasts a message to all connected clients +(define broadcast-message + (lambda (message connections) + (map send_message connections) + 'ok)) + +; port pair -> '(input-port output-port) + +(define (get-input-port port-pair) + (car port-pair)) + +(define (get-output-port port-pair) + (cadr port-pair)) + +;; gets pair of input and output port of a client and sends a message +(define send-message + (lambda (client_ports) + (displayln message (get-output-port (client-ports))) + (flush-output (get-output-port (client-ports))) + 'ok)) + + +;; + +;; This is a relay server making two clients communicate +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (serve 8080)) +;; (stop) to close the server + +(define (serve port-no) + (define main-cust (make-custodian)) + (parameterize ([current-custodian main-cust]) + (define listener (tcp-listen port-no 5 #t)) + (define (loop) + (accept-and-handle listener) + (loop)) + (thread loop)) + (lambda () + (displayln "\nGoodbye, shutting down all services\n") + (custodian-shutdown-all main-cust))) + +(define (accept-and-handle listener) + (define cust (make-custodian)) + (parameterize ([current-custodian cust]) + (define-values (in out) (tcp-accept listener)) + (semaphore-wait fair) + ;; keep track of open ports + (append connections (list (list in out))) + (semaphore-wait fiar) + + ; thread will communicate to all clients at once in a broadcast + ; manner + (thread (lambda () + (handle in out) ;; this handles connection with that specific client + (close-input-port in) + (close-output-port out))) + ) + ;; Watcher thread: + ;; kills current thread for waiting too long for connection from + ;; clients + (thread (lambda () + (sleep 120) + (custodian-shutdown-all cust)))) + +; (define (handle connections) +; ()) +;; each thread needs 2 new threads +(define (handle in out) + ; define function to deal with in + (define (something-to-say in) + (sync/timeout 4 (read-line-evt in 'linefeed))) + ; define function to deal with out + ; thread them each + ; (server-loop in out) + (sleep 5) ;; wait 5 seconds to guarantee client has already send message + (define echo (read-line in)) ;; bind message to echo + (displayln (string-append echo "\n")) + ; echo back the message, appending echo + ; could regex match the input to extract the name + (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back + (flush-output out) +) ;; This is a single server communicating directly to the client ;;;;;;;;;;;;;;;;;;;;;;Server Client communication;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -80,7 +173,6 @@ (display "What's your name?\n") (define username (read-line)) (define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt -(define fair (make-semaphore 1)) ;; intelligent read, quits when user types in "quit" (define (read-loop-i) @@ -128,4 +220,4 @@ ; (kill-thread t) ; (define a (thread (display "hello world!\n"))) ; (display "John: hello soso\n") -; (display "Emmanuel: cumbaya!!!!\n") \ No newline at end of file +; (display "Emmanuel: cumbaya!!!!\n") -- cgit v1.2.3 From 53bc7d0232eb8e8923d6721fcfd1d37925439c6e Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 12:59:00 -0400 Subject: cleaned up crpovertcp.rkt --- crpovertcp.rkt | 68 ---------------------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/crpovertcp.rkt b/crpovertcp.rkt index de04790..57874a8 100644 --- a/crpovertcp.rkt +++ b/crpovertcp.rkt @@ -14,28 +14,6 @@ (define can-i-broadcast (make-semaphore 1)) -;; alternative one keep running list of input and output ports directly -;; broadcasts a message to all connected clients -(define broadcast-message - (lambda (message connections) - (map send_message connections) - 'ok)) - -; port pair -> '(input-port output-port) - -(define (get-input-port port-pair) - (car port-pair)) - -(define (get-output-port port-pair) - (cadr port-pair)) - -;; gets pair of input and output port of a client and sends a message -(define send-message - (lambda (client_ports) - (displayln message (get-output-port (client-ports))) - (flush-output (get-output-port (client-ports))) - 'ok)) - ;; @@ -100,52 +78,6 @@ (flush-output out) ) ;; This is a single server communicating directly to the client - -;;;;;;;;;;;;;;;;;;;;;;Server Client communication;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define (serve in-port out-port) - (let loop [] - (define evt (sync/timeout 2 - (read-line-evt in-port 'any) - (thread-receive-evt))) - (cond - [(not evt) - (displayln "Timed out, exiting") - (tcp-abandon-port in-port) - (tcp-abandon-port out-port)] - [(string? evt) - (fprintf out-port "~a~n" evt) ;; echoes back received string - (flush-output out-port) ;; flushes the buffer - (loop)] ;; iterates again - [else - (printf "Received a message in mailbox: ~a~n" - (thread-receive)) - (loop)]))) - -(define port-num 4322) -(define (start-server) - (define listener (tcp-listen port-num)) - (thread - (lambda () - (let loop () ;; the server now loops continously listening in for connections - (define-values [in-port out-port] (tcp-accept listener)) - ;; lets add this open ports to global list of connections - (semaphore-wait fair) - (append connections (list (list in-port out-port))) - (semaphore-post fair) - (serve in-port out-port) ; could be do the greeting in here - (loop))))) - -(start-server) - -(define client-thread - (thread - (lambda () - (define-values [in-port out-port] (tcp-connect "localhost" port-num)) - - (display "first\nsecond\nthird\n" out-port) - (flush-output out-port) - ; copy-port will block until EOF is read from in-port - (copy-port in-port (current-output-port))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -- cgit v1.2.3 From 2e0ddaaf3a67659ea5448ea54bd563325d007021 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 13:02:30 -0400 Subject: partitioning crpovertcp.rkt to dedicated server.rkt and client.rkt files --- client.rkt | 77 ++++++++++++++++++++++++++++++ server.rkt | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 client.rkt create mode 100644 server.rkt diff --git a/client.rkt b/client.rkt new file mode 100644 index 0000000..70df4e6 --- /dev/null +++ b/client.rkt @@ -0,0 +1,77 @@ +#lang racket +(require math/base) ;; for random number generation + +;; author: Ibrahim Mkusa +;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 + +;; create custodian for managing all resources +;; so we can shutdown everything at once +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) +;; reads values continously from stdin and redisplays them +(define (read-loop) + (display (read-line)) + (display "\n") + (read-loop) + ) + +(define input-prompt "input: ") +(define output-prompt "output: ") + +(define fair (make-semaphore 1)) + +;; prompt for username and bind to a variable username +(display "What's your name?\n") +(define username (read-line)) +(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt + +;; intelligent read, quits when user types in "quit" +(define (read-loop-i) + + + ;(semaphore-wait fair) + (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (begin (kill-thread a) + (kill-thread t)))) + (display (string-append output-prompt input "\n")) + ;(semaphore-post fair) + (read-loop-i) + ) + + +;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port +(define (hello-world) + (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms + ;; with server + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + ;; at this time we simulate the input from different users + (define what-to-print (random-integer 0 2)) + (if (= what-to-print 0) + (display "Doug: What's up, up?\n") + (display "Fred: Looking good, good!\n")) + ;(semaphore-post fair) + (hello-world)) + +(define t (thread (lambda () + (read-loop-i)))) +(define a (thread (lambda () + (hello-world)))) + +(thread-wait t) ;; returns prompt back to drracket +;; below doesn't execute +; (sleep 10) +; (kill-thread t) +; (define a (thread (display "hello world!\n"))) +; (display "John: hello soso\n") +; (display "Emmanuel: cumbaya!!!!\n") diff --git a/server.rkt b/server.rkt new file mode 100644 index 0000000..57874a8 --- /dev/null +++ b/server.rkt @@ -0,0 +1,155 @@ +#lang racket +(require math/base) ;; for random number generation + +;; globals +;; must control access via semaphore as listener thread or broadcast thread +;; might need to access it +(define connections '()) ;; maintains a list of open ports +;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) + +;; lets keep thread descriptor values +; + +(define fair (make-semaphore 1)) ;; managing connections above + +(define can-i-broadcast (make-semaphore 1)) + + +;; + +;; This is a relay server making two clients communicate +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (serve 8080)) +;; (stop) to close the server + +(define (serve port-no) + (define main-cust (make-custodian)) + (parameterize ([current-custodian main-cust]) + (define listener (tcp-listen port-no 5 #t)) + (define (loop) + (accept-and-handle listener) + (loop)) + (thread loop)) + (lambda () + (displayln "\nGoodbye, shutting down all services\n") + (custodian-shutdown-all main-cust))) + +(define (accept-and-handle listener) + (define cust (make-custodian)) + (parameterize ([current-custodian cust]) + (define-values (in out) (tcp-accept listener)) + (semaphore-wait fair) + ;; keep track of open ports + (append connections (list (list in out))) + (semaphore-wait fiar) + + ; thread will communicate to all clients at once in a broadcast + ; manner + (thread (lambda () + (handle in out) ;; this handles connection with that specific client + (close-input-port in) + (close-output-port out))) + ) + ;; Watcher thread: + ;; kills current thread for waiting too long for connection from + ;; clients + (thread (lambda () + (sleep 120) + (custodian-shutdown-all cust)))) + +; (define (handle connections) +; ()) +;; each thread needs 2 new threads +(define (handle in out) + ; define function to deal with in + (define (something-to-say in) + (sync/timeout 4 (read-line-evt in 'linefeed))) + ; define function to deal with out + ; thread them each + ; (server-loop in out) + (sleep 5) ;; wait 5 seconds to guarantee client has already send message + (define echo (read-line in)) ;; bind message to echo + (displayln (string-append echo "\n")) + ; echo back the message, appending echo + ; could regex match the input to extract the name + (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back + (flush-output out) +) +;; This is a single server communicating directly to the client +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;; author: Ibrahim Mkusa +;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 + +;; create custodian for managing all resources +;; so we can shutdown everything at once +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) +;; reads values continously from stdin and redisplays them +(define (read-loop) + (display (read-line)) + (display "\n") + (read-loop) + ) + +(define input-prompt "input: ") +(define output-prompt "output: ") + +;; prompt for username and bind to a variable username +(display "What's your name?\n") +(define username (read-line)) +(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt + +;; intelligent read, quits when user types in "quit" +(define (read-loop-i) + + + ;(semaphore-wait fair) + (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (begin (kill-thread a) + (kill-thread t)))) + (display (string-append output-prompt input "\n")) + ;(semaphore-post fair) + (read-loop-i) + ) + + +;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port +(define (hello-world) + (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms + ;; with server + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + ;; at this time we simulate the input from different users + (define what-to-print (random-integer 0 2)) + (if (= what-to-print 0) + (display "Doug: What's up, up?\n") + (display "Fred: Looking good, good!\n")) + ;(semaphore-post fair) + (hello-world)) + +(define t (thread (lambda () + (read-loop-i)))) +(define a (thread (lambda () + (hello-world)))) + +(thread-wait t) ;; returns prompt back to drracket +;; below doesn't execute +; (sleep 10) +; (kill-thread t) +; (define a (thread (display "hello world!\n"))) +; (display "John: hello soso\n") +; (display "Emmanuel: cumbaya!!!!\n") -- cgit v1.2.3 From f56f1cc46d738bc76820977af8c6a372f9702df4 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 14:56:46 -0400 Subject: server code for interacting with client is done, not tested. Working on server broadcast function --- server.rkt | 150 ++++++++++++++++++++++--------------------------------------- 1 file changed, 54 insertions(+), 96 deletions(-) diff --git a/server.rkt b/server.rkt index 57874a8..c5bb6f3 100644 --- a/server.rkt +++ b/server.rkt @@ -6,11 +6,24 @@ ;; might need to access it (define connections '()) ;; maintains a list of open ports ;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) +(define connections-s (make-semaphore 1)) ;; control access to connections +;; every 5 seconds run to broadcast top message in list +;; and remove it from list +(define messages-s (make-semaphore 1)) ;; control access to messages +(define messages '()) ;; stores a list of messages(strings) from currents + +(define threads-s (make-semaphore 1)) ;; control access to threads ;; lets keep thread descriptor values -; +(define threads '()) ;; stores a list of client serving threads as thread descriptor values -(define fair (make-semaphore 1)) ;; managing connections above +;; define a broadcast function +(define broadcast + (lambda () + (semaphore-wait messages-s) + (semaphore-wait threads-s) + (map (lambda (thread-descriptor) + ())))) (define can-i-broadcast (make-semaphore 1)) @@ -40,116 +53,61 @@ (define cust (make-custodian)) (parameterize ([current-custodian cust]) (define-values (in out) (tcp-accept listener)) - (semaphore-wait fair) + (semaphore-wait connections-s) ;; keep track of open ports (append connections (list (list in out))) - (semaphore-wait fiar) + (semaphore-wait connections-s) - ; thread will communicate to all clients at once in a broadcast - ; manner - (thread (lambda () + ; start a thread to deal with specific client and add descriptor value to the list of threads + (append threads (list (thread (lambda () (handle in out) ;; this handles connection with that specific client (close-input-port in) - (close-output-port out))) - ) + (close-output-port out)))) + ) ;; Watcher thread: ;; kills current thread for waiting too long for connection from ;; clients (thread (lambda () (sleep 120) - (custodian-shutdown-all cust)))) + (custodian-shutdown-all cust))))) ; (define (handle connections) ; ()) ;; each thread needs 2 new threads (define (handle in out) - ; define function to deal with in + ; define function to deal with incoming messages from client (define (something-to-say in) - (sync/timeout 4 (read-line-evt in 'linefeed))) + (define evt-t0 (sync/timeout 120 (read-line-evt in 'linefeed))) + (cond [(not evt-t0) + (displayln "Nothing received from " (current-thread) "exiting")] + [(string? evt-t0) + (semaphore-wait messages-s) + ; append the message to list of messages + (append messages (list evt-t0)) + (semaphore-post messages-s)])) + + ; define function to deal with out + (define (something-to-send out) + (define evt-t1 (sync/timeout 120 (thread-receive-evt))) + ;; send message to client + (fprintf out "~a~n" (thread-receive)) + (flush-output out) + ) ; thread them each + + ;; i could bind to values, and call wait on them + ;; thread that deals with incoming messages for that particular thread + (thread (lambda () + (let loop [] + (something-to-say in) + (loop)))) + + (thread (lambda () + (let loop [] + (something-to-say out) + (loop)))) ; (server-loop in out) - (sleep 5) ;; wait 5 seconds to guarantee client has already send message - (define echo (read-line in)) ;; bind message to echo - (displayln (string-append echo "\n")) - ; echo back the message, appending echo - ; could regex match the input to extract the name - (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back - (flush-output out) -) -;; This is a single server communicating directly to the client -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; author: Ibrahim Mkusa -;; about: print and read concurrently -;; notes: output may need to be aligned and formatted nicely -;; look into -;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 - -;; create custodian for managing all resources -;; so we can shutdown everything at once -;(define guard (make-custodian (current-custodian))) -;(current-custodian guard) -;; reads values continously from stdin and redisplays them -(define (read-loop) - (display (read-line)) - (display "\n") - (read-loop) - ) - -(define input-prompt "input: ") -(define output-prompt "output: ") - -;; prompt for username and bind to a variable username -(display "What's your name?\n") -(define username (read-line)) -(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt - -;; intelligent read, quits when user types in "quit" -(define (read-loop-i) - - - ;(semaphore-wait fair) - (display usernamei) - (define input (read-line)) - ;; do something over here with input maybe send it out - - ;; Tests input if its a quit then kills all threads - ;; An if would be better here tbh - (cond ((string=? input "quit") (begin (kill-thread a) - (kill-thread t)))) - (display (string-append output-prompt input "\n")) - ;(semaphore-post fair) - (read-loop-i) - ) - - -;; print hello world continously -;; "(hello-world)" can be executed as part of background thread -;; that prints in the event there is something in the input port -(define (hello-world) - (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms - ;; with server - ;(semaphore-wait fair) - ;; we will retrieve the line printed below from the server - ;; at this time we simulate the input from different users - (define what-to-print (random-integer 0 2)) - (if (= what-to-print 0) - (display "Doug: What's up, up?\n") - (display "Fred: Looking good, good!\n")) - ;(semaphore-post fair) - (hello-world)) - -(define t (thread (lambda () - (read-loop-i)))) -(define a (thread (lambda () - (hello-world)))) - -(thread-wait t) ;; returns prompt back to drracket -;; below doesn't execute -; (sleep 10) -; (kill-thread t) -; (define a (thread (display "hello world!\n"))) -; (display "John: hello soso\n") -; (display "Emmanuel: cumbaya!!!!\n") + ; (sleep 5) ;; wait 5 seconds to guarantee client has already send message + 'ok + ) -- cgit v1.2.3 From ba3f6821f5ef38b6e2e1990581765f80203817c9 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 15:19:57 -0400 Subject: server.rkt is done, with exception of testing. Moving on to client.rkt --- client.rkt | 2 ++ server.rkt | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/client.rkt b/client.rkt index 70df4e6..f0d3578 100644 --- a/client.rkt +++ b/client.rkt @@ -12,6 +12,8 @@ ;(define guard (make-custodian (current-custodian))) ;(current-custodian guard) ;; reads values continously from stdin and redisplays them + +;;;;;; NOT IN USE ;;;;;;; (define (read-loop) (display (read-line)) (display "\n") diff --git a/server.rkt b/server.rkt index c5bb6f3..5322a3d 100644 --- a/server.rkt +++ b/server.rkt @@ -22,11 +22,15 @@ (lambda () (semaphore-wait messages-s) (semaphore-wait threads-s) - (map (lambda (thread-descriptor) - ())))) - -(define can-i-broadcast (make-semaphore 1)) - + (if (not (null? messages)) + (begin (map (lambda (thread-descriptor) + (thread-send thread-descriptor (first messages)))) + (set! messages (rest messages)) + ) + (display "No message to display\n") ; for later create file port for errors and save error messages to that file + ) + (semaphore-post threads-s) + (semaphore-post messages-s))) ;; @@ -44,7 +48,13 @@ (define (loop) (accept-and-handle listener) (loop)) - (thread loop)) + (thread loop) + ;; Create a thread whose job is to simply call broadcast iteratively + (thread (lambda () + (let loopb [] + broadcast + (sleep 10) ;; sleep for 10 seconds between broadcasts + (loopb))))) (lambda () (displayln "\nGoodbye, shutting down all services\n") (custodian-shutdown-all main-cust))) -- cgit v1.2.3 From f0d361b49c80d9fb78c67f006ad49b1062e8ed64 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 20:50:20 -0400 Subject: updates to server.rkt and client.rkt --- client.rkt | 107 +++++++++++++++++++++++++++------------------ concurrentreadandprint.rkt | 2 +- server.rkt | 69 ++++++++++++++++++----------- 3 files changed, 109 insertions(+), 69 deletions(-) diff --git a/client.rkt b/client.rkt index f0d3578..25be149 100644 --- a/client.rkt +++ b/client.rkt @@ -13,67 +13,90 @@ ;(current-custodian guard) ;; reads values continously from stdin and redisplays them -;;;;;; NOT IN USE ;;;;;;; -(define (read-loop) - (display (read-line)) - (display "\n") - (read-loop) - ) +;; Notes connect to server on localhost +;; use client template of tcpvanilla +;; use event for read-write -(define input-prompt "input: ") -(define output-prompt "output: ") +;; modify read-loop-i +; read a value and send it to server via output-port -(define fair (make-semaphore 1)) +; is there something in the input port. If yes? display it +; in the hello world -;; prompt for username and bind to a variable username -(display "What's your name?\n") -(define username (read-line)) -(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt +; make connection to server +(define (client port-no) + (define main-client-cust (make-custodian)) + (parameterize ([current-custodian main-client-cust]) + ;; connect to server at port 8080 + (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values + (display in) + (displayln out) + ;; binds to multiple values akin to unpacking tuples in python + (display "What's your name?\n") + (define username (read-line)) -;; intelligent read, quits when user types in "quit" -(define (read-loop-i) - - + ; (thread (lambda () + ;; make threads 2 lines + (define a (thread + (lambda () + (let loop [] + (receive-messages in) + (sleep 1) + (loop))))) + (define t (thread + (lambda () + (let loop [] + (send-messages username out) + (sleep 1) + (loop))))) + (thread-wait t) ;; returns prompt back to drracket + (close-input-port in) + (close-output-port out)) + (custodian-shutdown-all main-client-cust)) + + +;; the send-messages +(define (send-messages username out) + ;; intelligent read, quits when user types in "quit" ;(semaphore-wait fair) - (display usernamei) + ; (display usernamei) (define input (read-line)) ;; do something over here with input maybe send it out ;; Tests input if its a quit then kills all threads ;; An if would be better here tbh - (cond ((string=? input "quit") (begin (kill-thread a) - (kill-thread t)))) - (display (string-append output-prompt input "\n")) + ;; (cond ((string=? input "quit") (begin (kill-thread a) + ;(kill-thread t)))) + (cond ((string=? input "quit") (exit))) + ;; modify to send messages to out port + (displayln (string-append username ": " input) out) + (flush-output out) + ;(semaphore-post fair) - (read-loop-i) - ) + ; (read-loop-i out) +) + ;; print hello world continously ;; "(hello-world)" can be executed as part of background thread ;; that prints in the event there is something in the input port -(define (hello-world) - (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms +(define (receive-messages in) + ; (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms ;; with server ;(semaphore-wait fair) ;; we will retrieve the line printed below from the server - ;; at this time we simulate the input from different users - (define what-to-print (random-integer 0 2)) - (if (= what-to-print 0) - (display "Doug: What's up, up?\n") - (display "Fred: Looking good, good!\n")) + (define evt (sync/timeout 30 (read-line-evt in))) + (cond [(eof-object? evt) + (displayln "Server connection closed") + (exit)] + [(string? evt) + (displayln evt)] ; could time stamp here or to send message + [else + (displayln (string-append "Nothing received from server for 2 minutes."))] + ) ;(semaphore-post fair) - (hello-world)) +) -(define t (thread (lambda () - (read-loop-i)))) -(define a (thread (lambda () - (hello-world)))) +(define stop (client 4321)) -(thread-wait t) ;; returns prompt back to drracket -;; below doesn't execute -; (sleep 10) -; (kill-thread t) -; (define a (thread (display "hello world!\n"))) -; (display "John: hello soso\n") -; (display "Emmanuel: cumbaya!!!!\n") diff --git a/concurrentreadandprint.rkt b/concurrentreadandprint.rkt index 84882b4..f67f1dd 100644 --- a/concurrentreadandprint.rkt +++ b/concurrentreadandprint.rkt @@ -74,4 +74,4 @@ ; (kill-thread t) ; (define a (thread (display "hello world!\n"))) ; (display "John: hello soso\n") -; (display "Emmanuel: cumbaya!!!!\n") \ No newline at end of file +; (display "Emmanuel: cumbaya!!!!\n") diff --git a/server.rkt b/server.rkt index 5322a3d..d1f5a98 100644 --- a/server.rkt +++ b/server.rkt @@ -11,26 +11,13 @@ ;; every 5 seconds run to broadcast top message in list ;; and remove it from list (define messages-s (make-semaphore 1)) ;; control access to messages -(define messages '()) ;; stores a list of messages(strings) from currents +(define messages '("hello, world!")) ;; stores a list of messages(strings) from currents (define threads-s (make-semaphore 1)) ;; control access to threads ;; lets keep thread descriptor values (define threads '()) ;; stores a list of client serving threads as thread descriptor values -;; define a broadcast function -(define broadcast - (lambda () - (semaphore-wait messages-s) - (semaphore-wait threads-s) - (if (not (null? messages)) - (begin (map (lambda (thread-descriptor) - (thread-send thread-descriptor (first messages)))) - (set! messages (rest messages)) - ) - (display "No message to display\n") ; for later create file port for errors and save error messages to that file - ) - (semaphore-post threads-s) - (semaphore-post messages-s))) + ;; @@ -52,7 +39,8 @@ ;; Create a thread whose job is to simply call broadcast iteratively (thread (lambda () (let loopb [] - broadcast + (sleep 30) ;; wait 30 secs before beginning to broadcast + (broadcast) (sleep 10) ;; sleep for 10 seconds between broadcasts (loopb))))) (lambda () @@ -63,22 +51,26 @@ (define cust (make-custodian)) (parameterize ([current-custodian cust]) (define-values (in out) (tcp-accept listener)) + ; discard request header + ; Discard the request header (up to blank line): + (regexp-match #rx"(\r\n|^)\r\n" in) (semaphore-wait connections-s) ;; keep track of open ports - (append connections (list (list in out))) - (semaphore-wait connections-s) + (set! connections (append connections (list (list in out)))) + (semaphore-post connections-s) ; start a thread to deal with specific client and add descriptor value to the list of threads - (append threads (list (thread (lambda () + (set! threads (append threads (list (thread (lambda () (handle in out) ;; this handles connection with that specific client (close-input-port in) (close-output-port out)))) ) + ) ;; Watcher thread: ;; kills current thread for waiting too long for connection from ;; clients (thread (lambda () - (sleep 120) + (sleep 360) (custodian-shutdown-all cust))))) ; (define (handle connections) @@ -87,14 +79,19 @@ (define (handle in out) ; define function to deal with incoming messages from client (define (something-to-say in) - (define evt-t0 (sync/timeout 120 (read-line-evt in 'linefeed))) - (cond [(not evt-t0) - (displayln "Nothing received from " (current-thread) "exiting")] + (define evt-t0 (sync/timeout 30 (read-line-evt in 'linefeed))) + (cond [(eof-object? evt-t0) + (displayln (string-append "Connection closed " (current-thread) "exiting")) + (exit) + ] [(string? evt-t0) (semaphore-wait messages-s) ; append the message to list of messages - (append messages (list evt-t0)) - (semaphore-post messages-s)])) + (display (string-append evt-t0 "\n")) + (set! messages (append messages (list evt-t0))) + (semaphore-post messages-s)] + [else + (displayln (string-append "Nothing received from " (current-thread)))])) ; define function to deal with out @@ -111,13 +108,33 @@ (thread (lambda () (let loop [] (something-to-say in) + (sleep 1) (loop)))) (thread (lambda () (let loop [] - (something-to-say out) + (something-to-send out) + (sleep 1) (loop)))) ; (server-loop in out) ; (sleep 5) ;; wait 5 seconds to guarantee client has already send message 'ok ) + +;; define a broadcast function +(define broadcast + (lambda () + (semaphore-wait messages-s) + (semaphore-wait threads-s) + (if (not (null? messages)) + (begin (map (lambda (thread-descriptor) + (thread-send thread-descriptor (first messages))) + threads) + (set! messages (rest messages)) + ) + (display "No message to display\n") ; for later create file port for errors and save error messages to that file + ) + (semaphore-post threads-s) + (semaphore-post messages-s))) + +(define stop (serve 4321)) ;; start server then close with stop \ No newline at end of file -- cgit v1.2.3 From 404f3d7edfe648dc3fd51c1afc1b3984557f1902 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 22:29:59 -0400 Subject: Added tcpcommunication.rkt --- tcpcommunication.rkt | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tcpcommunication.rkt diff --git a/tcpcommunication.rkt b/tcpcommunication.rkt new file mode 100644 index 0000000..27a5151 --- /dev/null +++ b/tcpcommunication.rkt @@ -0,0 +1,57 @@ +#lang racket +(require math/base) ;; for random number generation + +(define listener (tcp-listen 4326 5 #t)) +(define a (thread (lambda () + (define-values (s-in s-out) (tcp-accept listener)) + ; Discard the request header (up to blank line): + ;(regexp-match #rx"(\r\n|^)\r\n" s-in) + (sleep 10) + (define (echo) + (define input (read-line s-in)) + (displayln input s-out) + (flush-output s-out) + (if (eof-object? input) + (displayln "Done talking\n") + (echo))) + (echo) + (close-input-port s-in) + (close-output-port s-out) + (tcp-close listener) + 'ok))) + +(define t (thread (lambda () + (define-values (c-in c-out) (tcp-connect "localhost" 4326)) + (define input-prompt "input: ") + (define output-prompt "output: ") + + ;; prompt for username and bind to a variable username + (display "What's your name?\n") + (define username (read-line)) + (define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt + (define fair (make-semaphore 1)) + + ;; intelligent read, quits when user types in "quit" + (define (read-loop-i) + ;(semaphore-wait fair) + ; (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (exit))) + (display (string-append output-prompt input "\n") c-out) + (flush-output c-out) + (displayln (read-line c-in)) ;; server echoes back sent input + ;(semaphore-post fair) + (read-loop-i) + ) + (read-loop-i) + 'ok))) + +;(kill-thread a) +;(kill-thread t) +(thread-wait t) +(display "DONE!!\n") + -- cgit v1.2.3 From cb381871d518077649be6272af823dabec2fcd28 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 22:37:50 -0400 Subject: reorganized repo a bit better --- FP4-instructions.md | 93 ----------------- Gui_Exploration.rkt | 129 ----------------------- Hermes/client.rkt | 102 ++++++++++++++++++ Hermes/concurrentreadandprint.rkt | 77 ++++++++++++++ Hermes/server.rkt | 140 +++++++++++++++++++++++++ Hermes/tcpcommunication.rkt | 57 ++++++++++ README.md | 4 +- arch_diagram.png | Bin 23853 -> 0 bytes architecture_diagram.png | Bin 65212 -> 0 bytes client.rkt | 102 ------------------ concurrentreadandprint.rkt | 77 -------------- crpovertcp.rkt | 155 ---------------------------- docs/FP4-instructions.md | 93 +++++++++++++++++ ext/arch_diagram.png | Bin 0 -> 23853 bytes ext/architecture_diagram.png | Bin 0 -> 65212 bytes feasibility_analysis/gui/windows.rkt | 9 -- feasibility_analysis/gui/windows2.rkt | 15 --- feasibility_analysis/tcpevents/README.md | 1 - feasibility_analysis/tcpevents/server.rkt | 39 ------- feasibility_analysis/tcpvanilla/README.md | 20 ---- feasibility_analysis/tcpvanilla/client.rkt | 72 ------------- feasibility_analysis/tcpvanilla/client2.rkt | 43 -------- feasibility_analysis/tcpvanilla/server.rkt | 58 ----------- feasibility_analysis/tcpvanilla/tcptalk.rkt | 30 ------ server.rkt | 140 ------------------------- tcpcommunication.rkt | 57 ---------- tests/gui/Gui_Exploration.rkt | 129 +++++++++++++++++++++++ tests/gui/windows.rkt | 9 ++ tests/gui/windows2.rkt | 15 +++ tests/tcpevents/README.md | 1 + tests/tcpevents/crpovertcp.rkt | 155 ++++++++++++++++++++++++++++ tests/tcpevents/server.rkt | 39 +++++++ tests/tcpvanilla/README.md | 20 ++++ tests/tcpvanilla/client.rkt | 72 +++++++++++++ tests/tcpvanilla/client2.rkt | 43 ++++++++ tests/tcpvanilla/server.rkt | 58 +++++++++++ tests/tcpvanilla/tcptalk.rkt | 30 ++++++ 37 files changed, 1042 insertions(+), 1042 deletions(-) delete mode 100644 FP4-instructions.md delete mode 100644 Gui_Exploration.rkt create mode 100644 Hermes/client.rkt create mode 100644 Hermes/concurrentreadandprint.rkt create mode 100644 Hermes/server.rkt create mode 100644 Hermes/tcpcommunication.rkt delete mode 100644 arch_diagram.png delete mode 100644 architecture_diagram.png delete mode 100644 client.rkt delete mode 100644 concurrentreadandprint.rkt delete mode 100644 crpovertcp.rkt create mode 100644 docs/FP4-instructions.md create mode 100644 ext/arch_diagram.png create mode 100644 ext/architecture_diagram.png delete mode 100644 feasibility_analysis/gui/windows.rkt delete mode 100644 feasibility_analysis/gui/windows2.rkt delete mode 100644 feasibility_analysis/tcpevents/README.md delete mode 100644 feasibility_analysis/tcpevents/server.rkt delete mode 100644 feasibility_analysis/tcpvanilla/README.md delete mode 100644 feasibility_analysis/tcpvanilla/client.rkt delete mode 100644 feasibility_analysis/tcpvanilla/client2.rkt delete mode 100644 feasibility_analysis/tcpvanilla/server.rkt delete mode 100644 feasibility_analysis/tcpvanilla/tcptalk.rkt delete mode 100644 server.rkt delete mode 100644 tcpcommunication.rkt create mode 100644 tests/gui/Gui_Exploration.rkt create mode 100644 tests/gui/windows.rkt create mode 100644 tests/gui/windows2.rkt create mode 100644 tests/tcpevents/README.md create mode 100644 tests/tcpevents/crpovertcp.rkt create mode 100644 tests/tcpevents/server.rkt create mode 100644 tests/tcpvanilla/README.md create mode 100644 tests/tcpvanilla/client.rkt create mode 100644 tests/tcpvanilla/client2.rkt create mode 100644 tests/tcpvanilla/server.rkt create mode 100644 tests/tcpvanilla/tcptalk.rkt diff --git a/FP4-instructions.md b/FP4-instructions.md deleted file mode 100644 index 6a04e91..0000000 --- a/FP4-instructions.md +++ /dev/null @@ -1,93 +0,0 @@ -# FP4-proposal - -**do not fork this** there are different directions - -## tl;dr - -1. Create a repository in [our organization][oplorg] for your project; add your teammate(s) as collaborators -2. Copy-paste this [template file](template.md) as the `README.md` file in your new repo; edit to become project plan -3. Make 3-slide slide show to be presented in class; insert into [class desk][gslides] -4. Enter project details into a new [Google form][projform] -5. Make a 0.1 release of your project (tagging `@fgmart`) - -## Due Date -* Sun Apr 2, 2017 at 11p - -## Instructions - -Teams will submit a single proposal, with sections that each member has done individually detailing their proposed contributions. The submission will be the `README.md` file in your brand-new project repository, which you'll make. - -You must start using GitHub collaboratively from this point forward. - -Instructions: - -1. Create a new repository for your project as part of [our organization][oplorg] - * Give it a name that you like—it may be your real names, usernames, or project name - * Add your teammates as collaborators (Settings > Collaborators & Teams > Add Collaborator) -2. Copy the content from the [template file](template.md) into your `README.md` - * Click the “Raw” button on the `template.md` file and then copy-paste into your repo's `README.md` edit view - * Save it - * *Then start editing it to become your actual proposal* -3. Everyone on the team contributes their sections to your `README.md` file. - * Use GitHub's collaboration features to make sure that each team member contributes meaningful content to the file - * At the absolute minimum, respective team members must have commits that show they have authored the section describing their planned contributions -4. Create a [github Release](https://help.github.com/articles/creating-releases/) of your repository. - * Version: v0.1 - * Title: Proposal - * Description: tag `@fgmart` - -And now some detail on what to write _in_ the report. - -**Overall guidance:** *You should be proposing something that you have high confidence that you can achieve, and the proposal should project that confidence.* - -The proposal should be no longer than necessary, but long enough to include critical detail. Diagrams are welcome. - -Remember, you can do some neat [formatting things with Markdown.][markdown] - -In case you missed it, here again is the [template file](template.md) - -## In-Class Presentation -Teams will each deliver an in-class presentation. Your team will have two minutes to present. - -The presentation shall have exactly three slides: - -1. Title - * project title (10 words or fewer) - * your real names - * each real name followed by GitHub username - * a relevant image of some sort (optional) -2. Overview - * a few short phrases describing the project - * a different relevant image (optional) -3. Architecture Diagram - * visual diagram showing the major components of the project - * include external things that your project will connect to - * include arrows showing flow of information - * internal components annotated with Racket libraries that they will use - * _important:_ annotate each block with the GH username of the person who is primarily responsible for its creation - -Make the slides in [Google Slides][gslides]. - -Then, import your deck into the [slide deck][martinslides]. You have write privileges based on your membership in the class forum. - -You and your teammates will give the presentation in class the day that this assignment is due. - -## Fill out Project Information Form - -Enter project details into a new [Google form][projform]. - -**This is absolutely necessary so I can keep track of all of the projects.** - -## Grading -The proposal must be submitted on time to receive credit. Late submissions will not be accepted for credit. - -You personally must be present in class (and participate in the presentation when it is your turn) to receive credit for the presentation. If your teammates are there and you are not, they will receive presentation credit and you will not. - - - -[forum]: https://groups.google.com/forum/#!forum/uml-opl-spr17 -[markdown]: https://help.github.com/articles/markdown-basics/ -[gslides]:https://slides.google.com -[martinslides]:https://docs.google.com/presentation/d/1fzNX4nV4z6IkLiVBMB0YD4CctlJxR9pWXSbYTOFcQvc -[projform]:https://goo.gl/forms/Gfh9hWBgvg323j6M2 -[oplorg]:https://github.com/oplS17projects/ diff --git a/Gui_Exploration.rkt b/Gui_Exploration.rkt deleted file mode 100644 index ff4d2d3..0000000 --- a/Gui_Exploration.rkt +++ /dev/null @@ -1,129 +0,0 @@ -#lang racket -(require racket/gui/base) -;;Step 1. Create a window to draw into -(define frame(new frame% [label "Example"])) -;;I don't know what frame% means, but new must be a procedure -;;(send frame show #t) Running this command displays the frame -;;send appears to be a command to be a procedure that takes a frame -;; followed by a command and a boolean. -;;the boolean is fed into the command in this case -;;if you said #f it would close the window -;;that is usefull -;;Below is a slight expantion on example code -;;letting the button be a toggle -(define frame2 (new frame%[label "Example2"])) -(define msg (new message% [parent frame2] [label " Nothing "])) -(define thingy #t) -(define button-to-click (new button% - [parent frame2] - [label "Click"] - [callback (lambda (button event) - (if thingy - (begin (set! thingy #f) - (send msg set-label "Something")) - (begin (set! thingy #t) - (send msg set-label " Nothing "))))])) -;;Frames are okay ish for error messages but the real stuff is -;;in canvas stuff -(define my-canvas% - (class canvas% - (define/override (on-event event) - (send msg set-label "Canvas mouse")) - (define/override (on-char event) - (send msg set-label "Canvas keyboard")) - (super-new)));;Don't know what that one means - -(define canvas-thing (new my-canvas% [parent frame2]));;unfortunately -;;we still need to re-size it manually -;;Now I wonder if we could create a procedure to make any text -;;appear -(define frame3 (new frame%[label "Example3"])) -(define blank (new message% [parent frame3] [label " "])) -(define (make-text string) (begin (send blank set-label string))) -;(send frame3 show #t) -;(make-text "Hello World") works exactly fine. -;;Now lets do something more complicated -;;We want to create a procedure that creates a new line -;;each time it is called so... -(define frame4 (new frame%[label "Example4"])) -;;now blank4 should be a procedure to create multiple lines in the frame -(define (make-text-line string) (begin (new message% - [parent frame4] - [label string]))) -;;display with -;;(send frame4 show #t) -;;add text with -;;(make-text-line "Hello World!") -;;This works for not but there are a few problems -;;first of all the window starts really small and doesn't restrict -;;resizing. Second it is always in the middle of the frame -;;Third, once text is on screen there is no way to get it off -;;But we can do better -(define frame5 (new frame% - [label "Example5"] - [width 300] - [height 300])) -(define canvas5 (new canvas% [parent frame5] - [paint-callback - (lambda (canvas dc) - (send dc set-scale 3 3) - (send dc set-text-foreground "blue") - (send dc draw-text "Don't Panic!" 0 0))])) -;;above is the example code to write some simple text, however -;;we can apply this to what we learned above to make something abit -;;more -(define frame6 (new frame% - [label "Example6"] - [width 600] - [height 700])) -(define (make-color-text string color) - (begin (new canvas% - [parent frame6] - [paint-callback - (lambda (canvas dc) - (send dc set-text-foreground color) - (send dc draw-text string 0 0 #f))]))) -;;display with -;;(send frame6 show #t) -;;write text with -;;(make-color-text "Hello World!" "purple") -;;Okay that doesn't exactly work as planned... -;;the problem with this is that each message is it's own canvas now -;;not only that but it means we can only print each line in it's -;;own color. So new plan is to make it so it adds on new strings -;;to one canvas, adding \n as nessessary. Except nevermind since -;;\n doesn't exist in this apparently - -;;Lets switch back to text and we can change it later -(define frame7 (new frame% - [label "Example7"] - [width 600] - [height 200])) -(define (make-blank-line i) - (new message% - [parent frame7] - [label " "])) -;;80 space characters -;;the i is only there to make the build-list command happy -(define Message-list (build-list 10 make-blank-line)) -;;10 make-blank-lines -;;that build-list command is super usefull for something like this -(define (move-down-list list) - (if (eq? '() (cdr list)) - '() - (begin - (move-down-list (cdr list)) - (send (car (cdr list)) set-label (send (car list) get-label))))) -(define (send-word string) - (begin - (move-down-list Message-list) - (send (car Message-list) set-label string))) -;;display with -;;(send frame7 show #t) -;;add text with -;;(send-word "Hello World") -;;Now using the send-word command I can make each word appear on the -;;screen in the place where it used to be. Starting at the top of the -;;screen and working it's way down the more text is added. -;;on the bottom line, after adding 10 lines of text, it will remove the bottom -;;most line \ No newline at end of file diff --git a/Hermes/client.rkt b/Hermes/client.rkt new file mode 100644 index 0000000..25be149 --- /dev/null +++ b/Hermes/client.rkt @@ -0,0 +1,102 @@ +#lang racket +(require math/base) ;; for random number generation + +;; author: Ibrahim Mkusa +;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 + +;; create custodian for managing all resources +;; so we can shutdown everything at once +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) +;; reads values continously from stdin and redisplays them + +;; Notes connect to server on localhost +;; use client template of tcpvanilla +;; use event for read-write + +;; modify read-loop-i +; read a value and send it to server via output-port + +; is there something in the input port. If yes? display it +; in the hello world + +; make connection to server +(define (client port-no) + (define main-client-cust (make-custodian)) + (parameterize ([current-custodian main-client-cust]) + ;; connect to server at port 8080 + (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values + (display in) + (displayln out) + ;; binds to multiple values akin to unpacking tuples in python + (display "What's your name?\n") + (define username (read-line)) + + ; (thread (lambda () + ;; make threads 2 lines + (define a (thread + (lambda () + (let loop [] + (receive-messages in) + (sleep 1) + (loop))))) + (define t (thread + (lambda () + (let loop [] + (send-messages username out) + (sleep 1) + (loop))))) + (thread-wait t) ;; returns prompt back to drracket + (close-input-port in) + (close-output-port out)) + (custodian-shutdown-all main-client-cust)) + + +;; the send-messages +(define (send-messages username out) + ;; intelligent read, quits when user types in "quit" + ;(semaphore-wait fair) + ; (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + ;; (cond ((string=? input "quit") (begin (kill-thread a) + ;(kill-thread t)))) + (cond ((string=? input "quit") (exit))) + ;; modify to send messages to out port + (displayln (string-append username ": " input) out) + (flush-output out) + + ;(semaphore-post fair) + ; (read-loop-i out) +) + + + +;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port +(define (receive-messages in) + ; (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms + ;; with server + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + (define evt (sync/timeout 30 (read-line-evt in))) + (cond [(eof-object? evt) + (displayln "Server connection closed") + (exit)] + [(string? evt) + (displayln evt)] ; could time stamp here or to send message + [else + (displayln (string-append "Nothing received from server for 2 minutes."))] + ) + ;(semaphore-post fair) +) + +(define stop (client 4321)) + diff --git a/Hermes/concurrentreadandprint.rkt b/Hermes/concurrentreadandprint.rkt new file mode 100644 index 0000000..f67f1dd --- /dev/null +++ b/Hermes/concurrentreadandprint.rkt @@ -0,0 +1,77 @@ +#lang racket +(require math/base) ;; for random number generation + + +;; author: Ibrahim Mkusa +;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 + +;; create custodian for managing all resources +;; so we can shutdown everything at once +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) +;; reads values continously from stdin and redisplays them +(define (read-loop) + (display (read-line)) + (display "\n") + (read-loop) + ) + +(define input-prompt "input: ") +(define output-prompt "output: ") + +;; prompt for username and bind to a variable username +(display "What's your name?\n") +(define username (read-line)) +(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt +(define fair (make-semaphore 1)) + +;; intelligent read, quits when user types in "quit" +(define (read-loop-i) + + + ;(semaphore-wait fair) + (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (begin (kill-thread a) + (kill-thread t)))) + (display (string-append output-prompt input "\n")) + ;(semaphore-post fair) + (read-loop-i) + ) + + +;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port +(define (hello-world) + (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms + ;; with server + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + ;; at this time we simulate the input from different users + (define what-to-print (random-integer 0 2)) + (if (= what-to-print 0) + (display "Doug: What's up, up?\n") + (display "Fred: Looking good, good!\n")) + ;(semaphore-post fair) + (hello-world)) + +(define t (thread (lambda () + (read-loop-i)))) +(define a (thread (lambda () + (hello-world)))) + +(thread-wait t) ;; returns prompt back to drracket +;; below doesn't execute +; (sleep 10) +; (kill-thread t) +; (define a (thread (display "hello world!\n"))) +; (display "John: hello soso\n") +; (display "Emmanuel: cumbaya!!!!\n") diff --git a/Hermes/server.rkt b/Hermes/server.rkt new file mode 100644 index 0000000..d1f5a98 --- /dev/null +++ b/Hermes/server.rkt @@ -0,0 +1,140 @@ +#lang racket +(require math/base) ;; for random number generation + +;; globals +;; must control access via semaphore as listener thread or broadcast thread +;; might need to access it +(define connections '()) ;; maintains a list of open ports +;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) +(define connections-s (make-semaphore 1)) ;; control access to connections + +;; every 5 seconds run to broadcast top message in list +;; and remove it from list +(define messages-s (make-semaphore 1)) ;; control access to messages +(define messages '("hello, world!")) ;; stores a list of messages(strings) from currents + +(define threads-s (make-semaphore 1)) ;; control access to threads +;; lets keep thread descriptor values +(define threads '()) ;; stores a list of client serving threads as thread descriptor values + + + +;; + +;; This is a relay server making two clients communicate +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (serve 8080)) +;; (stop) to close the server + +(define (serve port-no) + (define main-cust (make-custodian)) + (parameterize ([current-custodian main-cust]) + (define listener (tcp-listen port-no 5 #t)) + (define (loop) + (accept-and-handle listener) + (loop)) + (thread loop) + ;; Create a thread whose job is to simply call broadcast iteratively + (thread (lambda () + (let loopb [] + (sleep 30) ;; wait 30 secs before beginning to broadcast + (broadcast) + (sleep 10) ;; sleep for 10 seconds between broadcasts + (loopb))))) + (lambda () + (displayln "\nGoodbye, shutting down all services\n") + (custodian-shutdown-all main-cust))) + +(define (accept-and-handle listener) + (define cust (make-custodian)) + (parameterize ([current-custodian cust]) + (define-values (in out) (tcp-accept listener)) + ; discard request header + ; Discard the request header (up to blank line): + (regexp-match #rx"(\r\n|^)\r\n" in) + (semaphore-wait connections-s) + ;; keep track of open ports + (set! connections (append connections (list (list in out)))) + (semaphore-post connections-s) + + ; start a thread to deal with specific client and add descriptor value to the list of threads + (set! threads (append threads (list (thread (lambda () + (handle in out) ;; this handles connection with that specific client + (close-input-port in) + (close-output-port out)))) + ) + ) + ;; Watcher thread: + ;; kills current thread for waiting too long for connection from + ;; clients + (thread (lambda () + (sleep 360) + (custodian-shutdown-all cust))))) + +; (define (handle connections) +; ()) +;; each thread needs 2 new threads +(define (handle in out) + ; define function to deal with incoming messages from client + (define (something-to-say in) + (define evt-t0 (sync/timeout 30 (read-line-evt in 'linefeed))) + (cond [(eof-object? evt-t0) + (displayln (string-append "Connection closed " (current-thread) "exiting")) + (exit) + ] + [(string? evt-t0) + (semaphore-wait messages-s) + ; append the message to list of messages + (display (string-append evt-t0 "\n")) + (set! messages (append messages (list evt-t0))) + (semaphore-post messages-s)] + [else + (displayln (string-append "Nothing received from " (current-thread)))])) + + + ; define function to deal with out + (define (something-to-send out) + (define evt-t1 (sync/timeout 120 (thread-receive-evt))) + ;; send message to client + (fprintf out "~a~n" (thread-receive)) + (flush-output out) + ) + ; thread them each + + ;; i could bind to values, and call wait on them + ;; thread that deals with incoming messages for that particular thread + (thread (lambda () + (let loop [] + (something-to-say in) + (sleep 1) + (loop)))) + + (thread (lambda () + (let loop [] + (something-to-send out) + (sleep 1) + (loop)))) + ; (server-loop in out) + ; (sleep 5) ;; wait 5 seconds to guarantee client has already send message + 'ok + ) + +;; define a broadcast function +(define broadcast + (lambda () + (semaphore-wait messages-s) + (semaphore-wait threads-s) + (if (not (null? messages)) + (begin (map (lambda (thread-descriptor) + (thread-send thread-descriptor (first messages))) + threads) + (set! messages (rest messages)) + ) + (display "No message to display\n") ; for later create file port for errors and save error messages to that file + ) + (semaphore-post threads-s) + (semaphore-post messages-s))) + +(define stop (serve 4321)) ;; start server then close with stop \ No newline at end of file diff --git a/Hermes/tcpcommunication.rkt b/Hermes/tcpcommunication.rkt new file mode 100644 index 0000000..27a5151 --- /dev/null +++ b/Hermes/tcpcommunication.rkt @@ -0,0 +1,57 @@ +#lang racket +(require math/base) ;; for random number generation + +(define listener (tcp-listen 4326 5 #t)) +(define a (thread (lambda () + (define-values (s-in s-out) (tcp-accept listener)) + ; Discard the request header (up to blank line): + ;(regexp-match #rx"(\r\n|^)\r\n" s-in) + (sleep 10) + (define (echo) + (define input (read-line s-in)) + (displayln input s-out) + (flush-output s-out) + (if (eof-object? input) + (displayln "Done talking\n") + (echo))) + (echo) + (close-input-port s-in) + (close-output-port s-out) + (tcp-close listener) + 'ok))) + +(define t (thread (lambda () + (define-values (c-in c-out) (tcp-connect "localhost" 4326)) + (define input-prompt "input: ") + (define output-prompt "output: ") + + ;; prompt for username and bind to a variable username + (display "What's your name?\n") + (define username (read-line)) + (define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt + (define fair (make-semaphore 1)) + + ;; intelligent read, quits when user types in "quit" + (define (read-loop-i) + ;(semaphore-wait fair) + ; (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (exit))) + (display (string-append output-prompt input "\n") c-out) + (flush-output c-out) + (displayln (read-line c-in)) ;; server echoes back sent input + ;(semaphore-post fair) + (read-loop-i) + ) + (read-loop-i) + 'ok))) + +;(kill-thread a) +;(kill-thread t) +(thread-wait t) +(display "DONE!!\n") + diff --git a/README.md b/README.md index 4b247b0..2807b00 100644 --- a/README.md +++ b/README.md @@ -72,11 +72,11 @@ satisfactorily we would have met our goals. ## Architecture Diagram #### Preliminary design -![Architecture](https://github.com/oplS17projects/Hermes/blob/master/arch_diagram.png) +![Architecture](https://github.com/oplS17projects/Hermes/blob/master/ext/arch_diagram.png) #### The Game plan -![Diagram](https://github.com/oplS17projects/Hermes/blob/master/architecture_diagram.png) +![Diagram](https://github.com/oplS17projects/Hermes/blob/master/ext/architecture_diagram.png) ## Schedule diff --git a/arch_diagram.png b/arch_diagram.png deleted file mode 100644 index 6bb8803..0000000 Binary files a/arch_diagram.png and /dev/null differ diff --git a/architecture_diagram.png b/architecture_diagram.png deleted file mode 100644 index 1949ae0..0000000 Binary files a/architecture_diagram.png and /dev/null differ diff --git a/client.rkt b/client.rkt deleted file mode 100644 index 25be149..0000000 --- a/client.rkt +++ /dev/null @@ -1,102 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - -;; author: Ibrahim Mkusa -;; about: print and read concurrently -;; notes: output may need to be aligned and formatted nicely -;; look into -;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 - -;; create custodian for managing all resources -;; so we can shutdown everything at once -;(define guard (make-custodian (current-custodian))) -;(current-custodian guard) -;; reads values continously from stdin and redisplays them - -;; Notes connect to server on localhost -;; use client template of tcpvanilla -;; use event for read-write - -;; modify read-loop-i -; read a value and send it to server via output-port - -; is there something in the input port. If yes? display it -; in the hello world - -; make connection to server -(define (client port-no) - (define main-client-cust (make-custodian)) - (parameterize ([current-custodian main-client-cust]) - ;; connect to server at port 8080 - (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values - (display in) - (displayln out) - ;; binds to multiple values akin to unpacking tuples in python - (display "What's your name?\n") - (define username (read-line)) - - ; (thread (lambda () - ;; make threads 2 lines - (define a (thread - (lambda () - (let loop [] - (receive-messages in) - (sleep 1) - (loop))))) - (define t (thread - (lambda () - (let loop [] - (send-messages username out) - (sleep 1) - (loop))))) - (thread-wait t) ;; returns prompt back to drracket - (close-input-port in) - (close-output-port out)) - (custodian-shutdown-all main-client-cust)) - - -;; the send-messages -(define (send-messages username out) - ;; intelligent read, quits when user types in "quit" - ;(semaphore-wait fair) - ; (display usernamei) - (define input (read-line)) - ;; do something over here with input maybe send it out - - ;; Tests input if its a quit then kills all threads - ;; An if would be better here tbh - ;; (cond ((string=? input "quit") (begin (kill-thread a) - ;(kill-thread t)))) - (cond ((string=? input "quit") (exit))) - ;; modify to send messages to out port - (displayln (string-append username ": " input) out) - (flush-output out) - - ;(semaphore-post fair) - ; (read-loop-i out) -) - - - -;; print hello world continously -;; "(hello-world)" can be executed as part of background thread -;; that prints in the event there is something in the input port -(define (receive-messages in) - ; (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms - ;; with server - ;(semaphore-wait fair) - ;; we will retrieve the line printed below from the server - (define evt (sync/timeout 30 (read-line-evt in))) - (cond [(eof-object? evt) - (displayln "Server connection closed") - (exit)] - [(string? evt) - (displayln evt)] ; could time stamp here or to send message - [else - (displayln (string-append "Nothing received from server for 2 minutes."))] - ) - ;(semaphore-post fair) -) - -(define stop (client 4321)) - diff --git a/concurrentreadandprint.rkt b/concurrentreadandprint.rkt deleted file mode 100644 index f67f1dd..0000000 --- a/concurrentreadandprint.rkt +++ /dev/null @@ -1,77 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - - -;; author: Ibrahim Mkusa -;; about: print and read concurrently -;; notes: output may need to be aligned and formatted nicely -;; look into -;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 - -;; create custodian for managing all resources -;; so we can shutdown everything at once -;(define guard (make-custodian (current-custodian))) -;(current-custodian guard) -;; reads values continously from stdin and redisplays them -(define (read-loop) - (display (read-line)) - (display "\n") - (read-loop) - ) - -(define input-prompt "input: ") -(define output-prompt "output: ") - -;; prompt for username and bind to a variable username -(display "What's your name?\n") -(define username (read-line)) -(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt -(define fair (make-semaphore 1)) - -;; intelligent read, quits when user types in "quit" -(define (read-loop-i) - - - ;(semaphore-wait fair) - (display usernamei) - (define input (read-line)) - ;; do something over here with input maybe send it out - - ;; Tests input if its a quit then kills all threads - ;; An if would be better here tbh - (cond ((string=? input "quit") (begin (kill-thread a) - (kill-thread t)))) - (display (string-append output-prompt input "\n")) - ;(semaphore-post fair) - (read-loop-i) - ) - - -;; print hello world continously -;; "(hello-world)" can be executed as part of background thread -;; that prints in the event there is something in the input port -(define (hello-world) - (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms - ;; with server - ;(semaphore-wait fair) - ;; we will retrieve the line printed below from the server - ;; at this time we simulate the input from different users - (define what-to-print (random-integer 0 2)) - (if (= what-to-print 0) - (display "Doug: What's up, up?\n") - (display "Fred: Looking good, good!\n")) - ;(semaphore-post fair) - (hello-world)) - -(define t (thread (lambda () - (read-loop-i)))) -(define a (thread (lambda () - (hello-world)))) - -(thread-wait t) ;; returns prompt back to drracket -;; below doesn't execute -; (sleep 10) -; (kill-thread t) -; (define a (thread (display "hello world!\n"))) -; (display "John: hello soso\n") -; (display "Emmanuel: cumbaya!!!!\n") diff --git a/crpovertcp.rkt b/crpovertcp.rkt deleted file mode 100644 index 57874a8..0000000 --- a/crpovertcp.rkt +++ /dev/null @@ -1,155 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - -;; globals -;; must control access via semaphore as listener thread or broadcast thread -;; might need to access it -(define connections '()) ;; maintains a list of open ports -;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) - -;; lets keep thread descriptor values -; - -(define fair (make-semaphore 1)) ;; managing connections above - -(define can-i-broadcast (make-semaphore 1)) - - -;; - -;; This is a relay server making two clients communicate -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (serve 8080)) -;; (stop) to close the server - -(define (serve port-no) - (define main-cust (make-custodian)) - (parameterize ([current-custodian main-cust]) - (define listener (tcp-listen port-no 5 #t)) - (define (loop) - (accept-and-handle listener) - (loop)) - (thread loop)) - (lambda () - (displayln "\nGoodbye, shutting down all services\n") - (custodian-shutdown-all main-cust))) - -(define (accept-and-handle listener) - (define cust (make-custodian)) - (parameterize ([current-custodian cust]) - (define-values (in out) (tcp-accept listener)) - (semaphore-wait fair) - ;; keep track of open ports - (append connections (list (list in out))) - (semaphore-wait fiar) - - ; thread will communicate to all clients at once in a broadcast - ; manner - (thread (lambda () - (handle in out) ;; this handles connection with that specific client - (close-input-port in) - (close-output-port out))) - ) - ;; Watcher thread: - ;; kills current thread for waiting too long for connection from - ;; clients - (thread (lambda () - (sleep 120) - (custodian-shutdown-all cust)))) - -; (define (handle connections) -; ()) -;; each thread needs 2 new threads -(define (handle in out) - ; define function to deal with in - (define (something-to-say in) - (sync/timeout 4 (read-line-evt in 'linefeed))) - ; define function to deal with out - ; thread them each - ; (server-loop in out) - (sleep 5) ;; wait 5 seconds to guarantee client has already send message - (define echo (read-line in)) ;; bind message to echo - (displayln (string-append echo "\n")) - ; echo back the message, appending echo - ; could regex match the input to extract the name - (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back - (flush-output out) -) -;; This is a single server communicating directly to the client -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; author: Ibrahim Mkusa -;; about: print and read concurrently -;; notes: output may need to be aligned and formatted nicely -;; look into -;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 - -;; create custodian for managing all resources -;; so we can shutdown everything at once -;(define guard (make-custodian (current-custodian))) -;(current-custodian guard) -;; reads values continously from stdin and redisplays them -(define (read-loop) - (display (read-line)) - (display "\n") - (read-loop) - ) - -(define input-prompt "input: ") -(define output-prompt "output: ") - -;; prompt for username and bind to a variable username -(display "What's your name?\n") -(define username (read-line)) -(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt - -;; intelligent read, quits when user types in "quit" -(define (read-loop-i) - - - ;(semaphore-wait fair) - (display usernamei) - (define input (read-line)) - ;; do something over here with input maybe send it out - - ;; Tests input if its a quit then kills all threads - ;; An if would be better here tbh - (cond ((string=? input "quit") (begin (kill-thread a) - (kill-thread t)))) - (display (string-append output-prompt input "\n")) - ;(semaphore-post fair) - (read-loop-i) - ) - - -;; print hello world continously -;; "(hello-world)" can be executed as part of background thread -;; that prints in the event there is something in the input port -(define (hello-world) - (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms - ;; with server - ;(semaphore-wait fair) - ;; we will retrieve the line printed below from the server - ;; at this time we simulate the input from different users - (define what-to-print (random-integer 0 2)) - (if (= what-to-print 0) - (display "Doug: What's up, up?\n") - (display "Fred: Looking good, good!\n")) - ;(semaphore-post fair) - (hello-world)) - -(define t (thread (lambda () - (read-loop-i)))) -(define a (thread (lambda () - (hello-world)))) - -(thread-wait t) ;; returns prompt back to drracket -;; below doesn't execute -; (sleep 10) -; (kill-thread t) -; (define a (thread (display "hello world!\n"))) -; (display "John: hello soso\n") -; (display "Emmanuel: cumbaya!!!!\n") diff --git a/docs/FP4-instructions.md b/docs/FP4-instructions.md new file mode 100644 index 0000000..6a04e91 --- /dev/null +++ b/docs/FP4-instructions.md @@ -0,0 +1,93 @@ +# FP4-proposal + +**do not fork this** there are different directions + +## tl;dr + +1. Create a repository in [our organization][oplorg] for your project; add your teammate(s) as collaborators +2. Copy-paste this [template file](template.md) as the `README.md` file in your new repo; edit to become project plan +3. Make 3-slide slide show to be presented in class; insert into [class desk][gslides] +4. Enter project details into a new [Google form][projform] +5. Make a 0.1 release of your project (tagging `@fgmart`) + +## Due Date +* Sun Apr 2, 2017 at 11p + +## Instructions + +Teams will submit a single proposal, with sections that each member has done individually detailing their proposed contributions. The submission will be the `README.md` file in your brand-new project repository, which you'll make. + +You must start using GitHub collaboratively from this point forward. + +Instructions: + +1. Create a new repository for your project as part of [our organization][oplorg] + * Give it a name that you like—it may be your real names, usernames, or project name + * Add your teammates as collaborators (Settings > Collaborators & Teams > Add Collaborator) +2. Copy the content from the [template file](template.md) into your `README.md` + * Click the “Raw” button on the `template.md` file and then copy-paste into your repo's `README.md` edit view + * Save it + * *Then start editing it to become your actual proposal* +3. Everyone on the team contributes their sections to your `README.md` file. + * Use GitHub's collaboration features to make sure that each team member contributes meaningful content to the file + * At the absolute minimum, respective team members must have commits that show they have authored the section describing their planned contributions +4. Create a [github Release](https://help.github.com/articles/creating-releases/) of your repository. + * Version: v0.1 + * Title: Proposal + * Description: tag `@fgmart` + +And now some detail on what to write _in_ the report. + +**Overall guidance:** *You should be proposing something that you have high confidence that you can achieve, and the proposal should project that confidence.* + +The proposal should be no longer than necessary, but long enough to include critical detail. Diagrams are welcome. + +Remember, you can do some neat [formatting things with Markdown.][markdown] + +In case you missed it, here again is the [template file](template.md) + +## In-Class Presentation +Teams will each deliver an in-class presentation. Your team will have two minutes to present. + +The presentation shall have exactly three slides: + +1. Title + * project title (10 words or fewer) + * your real names + * each real name followed by GitHub username + * a relevant image of some sort (optional) +2. Overview + * a few short phrases describing the project + * a different relevant image (optional) +3. Architecture Diagram + * visual diagram showing the major components of the project + * include external things that your project will connect to + * include arrows showing flow of information + * internal components annotated with Racket libraries that they will use + * _important:_ annotate each block with the GH username of the person who is primarily responsible for its creation + +Make the slides in [Google Slides][gslides]. + +Then, import your deck into the [slide deck][martinslides]. You have write privileges based on your membership in the class forum. + +You and your teammates will give the presentation in class the day that this assignment is due. + +## Fill out Project Information Form + +Enter project details into a new [Google form][projform]. + +**This is absolutely necessary so I can keep track of all of the projects.** + +## Grading +The proposal must be submitted on time to receive credit. Late submissions will not be accepted for credit. + +You personally must be present in class (and participate in the presentation when it is your turn) to receive credit for the presentation. If your teammates are there and you are not, they will receive presentation credit and you will not. + + + +[forum]: https://groups.google.com/forum/#!forum/uml-opl-spr17 +[markdown]: https://help.github.com/articles/markdown-basics/ +[gslides]:https://slides.google.com +[martinslides]:https://docs.google.com/presentation/d/1fzNX4nV4z6IkLiVBMB0YD4CctlJxR9pWXSbYTOFcQvc +[projform]:https://goo.gl/forms/Gfh9hWBgvg323j6M2 +[oplorg]:https://github.com/oplS17projects/ diff --git a/ext/arch_diagram.png b/ext/arch_diagram.png new file mode 100644 index 0000000..6bb8803 Binary files /dev/null and b/ext/arch_diagram.png differ diff --git a/ext/architecture_diagram.png b/ext/architecture_diagram.png new file mode 100644 index 0000000..1949ae0 Binary files /dev/null and b/ext/architecture_diagram.png differ diff --git a/feasibility_analysis/gui/windows.rkt b/feasibility_analysis/gui/windows.rkt deleted file mode 100644 index 4524673..0000000 --- a/feasibility_analysis/gui/windows.rkt +++ /dev/null @@ -1,9 +0,0 @@ -#lang racket - -(require racket/gui/base) - -;; Create a new window via the frame class -(define frame (new frame% [label "Example"])) - -;; Show frame(window) by calling it show method -(send frame show #t) ;; you call object methods via send diff --git a/feasibility_analysis/gui/windows2.rkt b/feasibility_analysis/gui/windows2.rkt deleted file mode 100644 index 3f60c80..0000000 --- a/feasibility_analysis/gui/windows2.rkt +++ /dev/null @@ -1,15 +0,0 @@ -#lang racket - -(require racket/gui/base) - -(define frame (new frame% - [label "Example"] - [width 300] - [height 300])) -(new canvas% [parent frame] - [paint-callback - (lambda (canvas dc) - (send dc set-scale 3 3) - (send dc set-text-foreground "blue") - (send dc draw-text "Don't Panic!" 0 0))]) -(send frame show #t) diff --git a/feasibility_analysis/tcpevents/README.md b/feasibility_analysis/tcpevents/README.md deleted file mode 100644 index 7c3ec21..0000000 --- a/feasibility_analysis/tcpevents/README.md +++ /dev/null @@ -1 +0,0 @@ -TCP communication racket concepts of events. For more see the racket guide. diff --git a/feasibility_analysis/tcpevents/server.rkt b/feasibility_analysis/tcpevents/server.rkt deleted file mode 100644 index 4313bda..0000000 --- a/feasibility_analysis/tcpevents/server.rkt +++ /dev/null @@ -1,39 +0,0 @@ -#lang racket - -(define (serve in-port out-port) - (let loop [] - (define evt (sync/timeout 2 - (read-line-evt in-port 'any) - (thread-receive-evt))) - (cond - [(not evt) - (displayln "Timed out, exiting") - (tcp-abandon-port in-port) - (tcp-abandon-port out-port)] - [(string? evt) - (fprintf out-port "~a~n" evt) - (flush-output out-port) - (loop)] - [else - (printf "Received a message in mailbox: ~a~n" - (thread-receive)) - (loop)]))) - -(define port-num 4321) -(define (start-server) - (define listener (tcp-listen port-num)) - (thread - (lambda () - (define-values [in-port out-port] (tcp-accept listener)) - (serve in-port out-port)))) - -(start-server) - -(define client-thread - (thread - (lambda () - (define-values [in-port out-port] (tcp-connect "localhost" port-num)) - (display "first\nsecond\nthird\n" out-port) - (flush-output out-port) - ; copy-port will block until EOF is read from in-port - (copy-port in-port (current-output-port))))) diff --git a/feasibility_analysis/tcpvanilla/README.md b/feasibility_analysis/tcpvanilla/README.md deleted file mode 100644 index b8e2883..0000000 --- a/feasibility_analysis/tcpvanilla/README.md +++ /dev/null @@ -1,20 +0,0 @@ -a simple experiment on communication via tcp ports - -a server runs continously servicing clients. Clients connect, send a message, and -server replies with a message. Message should appear in each separate REPL area -prompt - -run server.rkt in a REPL -``` -,en server.rkt -(define stop (serve 8080)) ;; starts serve listening at port 8080 -(stop) ;; to stop server and free the ports - -``` - -run client.rkt in a separate REPL -``` -,en client.rkt -(define stop (client 8080)) ;; starts client talking to server at port 8080 - -``` diff --git a/feasibility_analysis/tcpvanilla/client.rkt b/feasibility_analysis/tcpvanilla/client.rkt deleted file mode 100644 index 967d2b9..0000000 --- a/feasibility_analysis/tcpvanilla/client.rkt +++ /dev/null @@ -1,72 +0,0 @@ -#lang racket - -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (client 8080)) -;; use your web browser to connect localhost:8080 greeted with "hello world" -;; (stop) to close the server - -(define (client port-no) - (define main-client-cust (make-custodian)) - (parameterize ([current-custodian main-client-cust]) - ;; connect to server at port 8080 - (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values - ;; binds to multiple values akin to unpacking tuples in python - ; (thread (lambda () - (chat in out) - (close-input-port in) - (close-output-port out)) - (custodian-shutdown-all main-client-cust)) - - ; (sleep 60) ;; run for 3 minutes then close - ; (define (loop) - ; (write (read-line (current-input-port)) out) - ; (flush-output out) - ; (write (read-line in) (current-output-port)) - ; (define listener (tcp-listen port-no 5 #t)) - ; (define (loop) - ; (accept-and-handle listener) - ; (loop)) - ; (thread loop))) - ; (custodian-shutdown-all main-client-cust) - #| (lambda () |# - ; (displayln "Goodbye, shutting down client\n") - #| (custodian-shutdown-all main-client-cust)) |# - -(define (chat in out) - ; (driver-loop in out) - (writeln "Ibrahim: Hello, anyone in chat?" out) - (flush-output out) ;; ports are buffered in racket must flush or you - ;; will read #eof - (sleep 10) ;; wait 10 seconds - (define serv-message (read-line in)) - (displayln serv-message) ;; read the servers replay message which is original - ;; with echo appended to it - ) - -; (define input-prompt "Hermes: ") - -(define (driver-loop in out) - ; (prompt-for-input input-prompt) - (display ">>> ") - (define input (read)) - (writeln (string-append "Ibrahim: " input) out) - (flush-output out) - ; (sleep 10) - (define output (read-line in)) - (displayln output) - (driver-loop in out)) - - -#| (let ((input (read))) |# -; ) -; (let ((input (read))) -; (let ((output (mc-eval input the-global-environment))) -; (announce-output output-prompt) -; (user-print output))) -; (driver-loop)) -; -; (define (announce-output string) -; (display string)) -#| |# diff --git a/feasibility_analysis/tcpvanilla/client2.rkt b/feasibility_analysis/tcpvanilla/client2.rkt deleted file mode 100644 index 47e3052..0000000 --- a/feasibility_analysis/tcpvanilla/client2.rkt +++ /dev/null @@ -1,43 +0,0 @@ -#lang racket - -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (client 8080)) -;; use your web browser to connect localhost:8080 greeted with "hello world" -;; (stop) to close the server - -(define (client port-no) - (define main-client-cust (make-custodian)) - (parameterize ([current-custodian main-client-cust]) - ;; connect to server at port 8080 - (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values - ;; binds to multiple values akin to unpacking tuples in python - (thread (lambda () - (send-message in out) - (close-input-port in) - (close-output-port out)))) - (sleep 20) - ; (define (loop) - ; (write (read-line (current-input-port)) out) - ; (flush-output out) - ; (write (read-line in) (current-output-port)) - ; (define listener (tcp-listen port-no 5 #t)) - ; (define (loop) - ; (accept-and-handle listener) - ; (loop)) - ; (thread loop))) - (custodian-shutdown-all main-client-cust) - #| (lambda () |# - ; (displayln "Goodbye, shutting down client\n") - #| (custodian-shutdown-all main-client-cust)) |#) - -(define (send-message input-port output-port) - (writeln "Doug: Hello, how's it going?" output-port) - (flush-output output-port) ;; ports are buffered in racket must flush or you - ;; will read #eof - (sleep 10) ;; wait 10 seconds - (define serv-message (read-line input-port)) - (displayln serv-message) ;; read the servers replay message which is original - ;; with echo appended to it - ) diff --git a/feasibility_analysis/tcpvanilla/server.rkt b/feasibility_analysis/tcpvanilla/server.rkt deleted file mode 100644 index bf72aff..0000000 --- a/feasibility_analysis/tcpvanilla/server.rkt +++ /dev/null @@ -1,58 +0,0 @@ -#lang racket - -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (serve 8080)) -;; use your web browser to connect localhost:8080 greeted with "hello world" -;; (stop) to close the server - -(define (serve port-no) - (define main-cust (make-custodian)) - (parameterize ([current-custodian main-cust]) - (define listener (tcp-listen port-no 5 #t)) - (define (loop) - (accept-and-handle listener) - (loop)) - (thread loop)) - (lambda () - (displayln "\nGoodbye, shutting down all services\n") - (custodian-shutdown-all main-cust))) - -(define (accept-and-handle listener) - (define cust (make-custodian)) - (parameterize ([current-custodian cust]) - (define-values (in out) (tcp-accept listener)) - (thread (lambda () - (handle in out) ;; this handles connection with that specific client - (close-input-port in) - (close-output-port out)))) - ;; Watcher thread: - (thread (lambda () - (sleep 120) - (custodian-shutdown-all cust)))) - -(define (handle in out) - ; (server-loop in out) - (sleep 5) ;; wait 5 seconds to guarantee client has already send message - (define echo (read-line in)) ;; bind message to echo - (displayln (string-append echo "\n")) - ; echo back the message, appending echo - ; could regex match the input to extract the name - (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back - (flush-output out) -) - -(define input-prompt "Hermes: ") - -(define (server-loop in out) - (define echo (read-line in)) - (displayln echo) - (display ">>> ") - - (define input (read)) - (writeln (string-append "Admin: " input) out) - (flush-output out) - ; (sleep 10) - (server-loop in out)) - diff --git a/feasibility_analysis/tcpvanilla/tcptalk.rkt b/feasibility_analysis/tcpvanilla/tcptalk.rkt deleted file mode 100644 index d069851..0000000 --- a/feasibility_analysis/tcpvanilla/tcptalk.rkt +++ /dev/null @@ -1,30 +0,0 @@ -#lang racket - -(define listener (tcp-listen 8083 5 #t)) ;; listener to service connection requests -;; client attempts to connect. Receives an input and output port -(define-values (client-in client-out) (tcp-connect "localhost" 8083)) -;; server accepts the connection request. Also gets a pair of ports -(define-values (server-in server-out) (tcp-accept listener)) - -;; client sends identifying message -(display (string-append "Client:My name is " "Ibrahim" "\n") - client-out) -(flush-output client-out) ;; must flush as ports are buffered in racket - -;; server receives and reads it -;; cooler if on separate racket instances -(read-line server-in) ;; --> "Client:My name is #hostname. -;; server replies -(display (string-append "Server:Hi " "Ibrahim" "\n") server-out) -(flush-output server-out) ;; flush flush - -;; client displays server message -(read-line client-in) -(close-output-port server-out) -(close-output-port client-out) -(read-line client-in) ;; --> eof object #eof -(read-line server-in) ;; --> eof object #eof -(tcp-close listener) -; (custodian-shutdown-all (current-custodian)) ;; release all resources including - ;; tcp, file, custom ports - ;; application exits diff --git a/server.rkt b/server.rkt deleted file mode 100644 index d1f5a98..0000000 --- a/server.rkt +++ /dev/null @@ -1,140 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - -;; globals -;; must control access via semaphore as listener thread or broadcast thread -;; might need to access it -(define connections '()) ;; maintains a list of open ports -;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) -(define connections-s (make-semaphore 1)) ;; control access to connections - -;; every 5 seconds run to broadcast top message in list -;; and remove it from list -(define messages-s (make-semaphore 1)) ;; control access to messages -(define messages '("hello, world!")) ;; stores a list of messages(strings) from currents - -(define threads-s (make-semaphore 1)) ;; control access to threads -;; lets keep thread descriptor values -(define threads '()) ;; stores a list of client serving threads as thread descriptor values - - - -;; - -;; This is a relay server making two clients communicate -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (serve 8080)) -;; (stop) to close the server - -(define (serve port-no) - (define main-cust (make-custodian)) - (parameterize ([current-custodian main-cust]) - (define listener (tcp-listen port-no 5 #t)) - (define (loop) - (accept-and-handle listener) - (loop)) - (thread loop) - ;; Create a thread whose job is to simply call broadcast iteratively - (thread (lambda () - (let loopb [] - (sleep 30) ;; wait 30 secs before beginning to broadcast - (broadcast) - (sleep 10) ;; sleep for 10 seconds between broadcasts - (loopb))))) - (lambda () - (displayln "\nGoodbye, shutting down all services\n") - (custodian-shutdown-all main-cust))) - -(define (accept-and-handle listener) - (define cust (make-custodian)) - (parameterize ([current-custodian cust]) - (define-values (in out) (tcp-accept listener)) - ; discard request header - ; Discard the request header (up to blank line): - (regexp-match #rx"(\r\n|^)\r\n" in) - (semaphore-wait connections-s) - ;; keep track of open ports - (set! connections (append connections (list (list in out)))) - (semaphore-post connections-s) - - ; start a thread to deal with specific client and add descriptor value to the list of threads - (set! threads (append threads (list (thread (lambda () - (handle in out) ;; this handles connection with that specific client - (close-input-port in) - (close-output-port out)))) - ) - ) - ;; Watcher thread: - ;; kills current thread for waiting too long for connection from - ;; clients - (thread (lambda () - (sleep 360) - (custodian-shutdown-all cust))))) - -; (define (handle connections) -; ()) -;; each thread needs 2 new threads -(define (handle in out) - ; define function to deal with incoming messages from client - (define (something-to-say in) - (define evt-t0 (sync/timeout 30 (read-line-evt in 'linefeed))) - (cond [(eof-object? evt-t0) - (displayln (string-append "Connection closed " (current-thread) "exiting")) - (exit) - ] - [(string? evt-t0) - (semaphore-wait messages-s) - ; append the message to list of messages - (display (string-append evt-t0 "\n")) - (set! messages (append messages (list evt-t0))) - (semaphore-post messages-s)] - [else - (displayln (string-append "Nothing received from " (current-thread)))])) - - - ; define function to deal with out - (define (something-to-send out) - (define evt-t1 (sync/timeout 120 (thread-receive-evt))) - ;; send message to client - (fprintf out "~a~n" (thread-receive)) - (flush-output out) - ) - ; thread them each - - ;; i could bind to values, and call wait on them - ;; thread that deals with incoming messages for that particular thread - (thread (lambda () - (let loop [] - (something-to-say in) - (sleep 1) - (loop)))) - - (thread (lambda () - (let loop [] - (something-to-send out) - (sleep 1) - (loop)))) - ; (server-loop in out) - ; (sleep 5) ;; wait 5 seconds to guarantee client has already send message - 'ok - ) - -;; define a broadcast function -(define broadcast - (lambda () - (semaphore-wait messages-s) - (semaphore-wait threads-s) - (if (not (null? messages)) - (begin (map (lambda (thread-descriptor) - (thread-send thread-descriptor (first messages))) - threads) - (set! messages (rest messages)) - ) - (display "No message to display\n") ; for later create file port for errors and save error messages to that file - ) - (semaphore-post threads-s) - (semaphore-post messages-s))) - -(define stop (serve 4321)) ;; start server then close with stop \ No newline at end of file diff --git a/tcpcommunication.rkt b/tcpcommunication.rkt deleted file mode 100644 index 27a5151..0000000 --- a/tcpcommunication.rkt +++ /dev/null @@ -1,57 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - -(define listener (tcp-listen 4326 5 #t)) -(define a (thread (lambda () - (define-values (s-in s-out) (tcp-accept listener)) - ; Discard the request header (up to blank line): - ;(regexp-match #rx"(\r\n|^)\r\n" s-in) - (sleep 10) - (define (echo) - (define input (read-line s-in)) - (displayln input s-out) - (flush-output s-out) - (if (eof-object? input) - (displayln "Done talking\n") - (echo))) - (echo) - (close-input-port s-in) - (close-output-port s-out) - (tcp-close listener) - 'ok))) - -(define t (thread (lambda () - (define-values (c-in c-out) (tcp-connect "localhost" 4326)) - (define input-prompt "input: ") - (define output-prompt "output: ") - - ;; prompt for username and bind to a variable username - (display "What's your name?\n") - (define username (read-line)) - (define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt - (define fair (make-semaphore 1)) - - ;; intelligent read, quits when user types in "quit" - (define (read-loop-i) - ;(semaphore-wait fair) - ; (display usernamei) - (define input (read-line)) - ;; do something over here with input maybe send it out - - ;; Tests input if its a quit then kills all threads - ;; An if would be better here tbh - (cond ((string=? input "quit") (exit))) - (display (string-append output-prompt input "\n") c-out) - (flush-output c-out) - (displayln (read-line c-in)) ;; server echoes back sent input - ;(semaphore-post fair) - (read-loop-i) - ) - (read-loop-i) - 'ok))) - -;(kill-thread a) -;(kill-thread t) -(thread-wait t) -(display "DONE!!\n") - diff --git a/tests/gui/Gui_Exploration.rkt b/tests/gui/Gui_Exploration.rkt new file mode 100644 index 0000000..ff4d2d3 --- /dev/null +++ b/tests/gui/Gui_Exploration.rkt @@ -0,0 +1,129 @@ +#lang racket +(require racket/gui/base) +;;Step 1. Create a window to draw into +(define frame(new frame% [label "Example"])) +;;I don't know what frame% means, but new must be a procedure +;;(send frame show #t) Running this command displays the frame +;;send appears to be a command to be a procedure that takes a frame +;; followed by a command and a boolean. +;;the boolean is fed into the command in this case +;;if you said #f it would close the window +;;that is usefull +;;Below is a slight expantion on example code +;;letting the button be a toggle +(define frame2 (new frame%[label "Example2"])) +(define msg (new message% [parent frame2] [label " Nothing "])) +(define thingy #t) +(define button-to-click (new button% + [parent frame2] + [label "Click"] + [callback (lambda (button event) + (if thingy + (begin (set! thingy #f) + (send msg set-label "Something")) + (begin (set! thingy #t) + (send msg set-label " Nothing "))))])) +;;Frames are okay ish for error messages but the real stuff is +;;in canvas stuff +(define my-canvas% + (class canvas% + (define/override (on-event event) + (send msg set-label "Canvas mouse")) + (define/override (on-char event) + (send msg set-label "Canvas keyboard")) + (super-new)));;Don't know what that one means + +(define canvas-thing (new my-canvas% [parent frame2]));;unfortunately +;;we still need to re-size it manually +;;Now I wonder if we could create a procedure to make any text +;;appear +(define frame3 (new frame%[label "Example3"])) +(define blank (new message% [parent frame3] [label " "])) +(define (make-text string) (begin (send blank set-label string))) +;(send frame3 show #t) +;(make-text "Hello World") works exactly fine. +;;Now lets do something more complicated +;;We want to create a procedure that creates a new line +;;each time it is called so... +(define frame4 (new frame%[label "Example4"])) +;;now blank4 should be a procedure to create multiple lines in the frame +(define (make-text-line string) (begin (new message% + [parent frame4] + [label string]))) +;;display with +;;(send frame4 show #t) +;;add text with +;;(make-text-line "Hello World!") +;;This works for not but there are a few problems +;;first of all the window starts really small and doesn't restrict +;;resizing. Second it is always in the middle of the frame +;;Third, once text is on screen there is no way to get it off +;;But we can do better +(define frame5 (new frame% + [label "Example5"] + [width 300] + [height 300])) +(define canvas5 (new canvas% [parent frame5] + [paint-callback + (lambda (canvas dc) + (send dc set-scale 3 3) + (send dc set-text-foreground "blue") + (send dc draw-text "Don't Panic!" 0 0))])) +;;above is the example code to write some simple text, however +;;we can apply this to what we learned above to make something abit +;;more +(define frame6 (new frame% + [label "Example6"] + [width 600] + [height 700])) +(define (make-color-text string color) + (begin (new canvas% + [parent frame6] + [paint-callback + (lambda (canvas dc) + (send dc set-text-foreground color) + (send dc draw-text string 0 0 #f))]))) +;;display with +;;(send frame6 show #t) +;;write text with +;;(make-color-text "Hello World!" "purple") +;;Okay that doesn't exactly work as planned... +;;the problem with this is that each message is it's own canvas now +;;not only that but it means we can only print each line in it's +;;own color. So new plan is to make it so it adds on new strings +;;to one canvas, adding \n as nessessary. Except nevermind since +;;\n doesn't exist in this apparently + +;;Lets switch back to text and we can change it later +(define frame7 (new frame% + [label "Example7"] + [width 600] + [height 200])) +(define (make-blank-line i) + (new message% + [parent frame7] + [label " "])) +;;80 space characters +;;the i is only there to make the build-list command happy +(define Message-list (build-list 10 make-blank-line)) +;;10 make-blank-lines +;;that build-list command is super usefull for something like this +(define (move-down-list list) + (if (eq? '() (cdr list)) + '() + (begin + (move-down-list (cdr list)) + (send (car (cdr list)) set-label (send (car list) get-label))))) +(define (send-word string) + (begin + (move-down-list Message-list) + (send (car Message-list) set-label string))) +;;display with +;;(send frame7 show #t) +;;add text with +;;(send-word "Hello World") +;;Now using the send-word command I can make each word appear on the +;;screen in the place where it used to be. Starting at the top of the +;;screen and working it's way down the more text is added. +;;on the bottom line, after adding 10 lines of text, it will remove the bottom +;;most line \ No newline at end of file diff --git a/tests/gui/windows.rkt b/tests/gui/windows.rkt new file mode 100644 index 0000000..4524673 --- /dev/null +++ b/tests/gui/windows.rkt @@ -0,0 +1,9 @@ +#lang racket + +(require racket/gui/base) + +;; Create a new window via the frame class +(define frame (new frame% [label "Example"])) + +;; Show frame(window) by calling it show method +(send frame show #t) ;; you call object methods via send diff --git a/tests/gui/windows2.rkt b/tests/gui/windows2.rkt new file mode 100644 index 0000000..3f60c80 --- /dev/null +++ b/tests/gui/windows2.rkt @@ -0,0 +1,15 @@ +#lang racket + +(require racket/gui/base) + +(define frame (new frame% + [label "Example"] + [width 300] + [height 300])) +(new canvas% [parent frame] + [paint-callback + (lambda (canvas dc) + (send dc set-scale 3 3) + (send dc set-text-foreground "blue") + (send dc draw-text "Don't Panic!" 0 0))]) +(send frame show #t) diff --git a/tests/tcpevents/README.md b/tests/tcpevents/README.md new file mode 100644 index 0000000..7c3ec21 --- /dev/null +++ b/tests/tcpevents/README.md @@ -0,0 +1 @@ +TCP communication racket concepts of events. For more see the racket guide. diff --git a/tests/tcpevents/crpovertcp.rkt b/tests/tcpevents/crpovertcp.rkt new file mode 100644 index 0000000..57874a8 --- /dev/null +++ b/tests/tcpevents/crpovertcp.rkt @@ -0,0 +1,155 @@ +#lang racket +(require math/base) ;; for random number generation + +;; globals +;; must control access via semaphore as listener thread or broadcast thread +;; might need to access it +(define connections '()) ;; maintains a list of open ports +;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) + +;; lets keep thread descriptor values +; + +(define fair (make-semaphore 1)) ;; managing connections above + +(define can-i-broadcast (make-semaphore 1)) + + +;; + +;; This is a relay server making two clients communicate +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (serve 8080)) +;; (stop) to close the server + +(define (serve port-no) + (define main-cust (make-custodian)) + (parameterize ([current-custodian main-cust]) + (define listener (tcp-listen port-no 5 #t)) + (define (loop) + (accept-and-handle listener) + (loop)) + (thread loop)) + (lambda () + (displayln "\nGoodbye, shutting down all services\n") + (custodian-shutdown-all main-cust))) + +(define (accept-and-handle listener) + (define cust (make-custodian)) + (parameterize ([current-custodian cust]) + (define-values (in out) (tcp-accept listener)) + (semaphore-wait fair) + ;; keep track of open ports + (append connections (list (list in out))) + (semaphore-wait fiar) + + ; thread will communicate to all clients at once in a broadcast + ; manner + (thread (lambda () + (handle in out) ;; this handles connection with that specific client + (close-input-port in) + (close-output-port out))) + ) + ;; Watcher thread: + ;; kills current thread for waiting too long for connection from + ;; clients + (thread (lambda () + (sleep 120) + (custodian-shutdown-all cust)))) + +; (define (handle connections) +; ()) +;; each thread needs 2 new threads +(define (handle in out) + ; define function to deal with in + (define (something-to-say in) + (sync/timeout 4 (read-line-evt in 'linefeed))) + ; define function to deal with out + ; thread them each + ; (server-loop in out) + (sleep 5) ;; wait 5 seconds to guarantee client has already send message + (define echo (read-line in)) ;; bind message to echo + (displayln (string-append echo "\n")) + ; echo back the message, appending echo + ; could regex match the input to extract the name + (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back + (flush-output out) +) +;; This is a single server communicating directly to the client +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;; author: Ibrahim Mkusa +;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 + +;; create custodian for managing all resources +;; so we can shutdown everything at once +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) +;; reads values continously from stdin and redisplays them +(define (read-loop) + (display (read-line)) + (display "\n") + (read-loop) + ) + +(define input-prompt "input: ") +(define output-prompt "output: ") + +;; prompt for username and bind to a variable username +(display "What's your name?\n") +(define username (read-line)) +(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt + +;; intelligent read, quits when user types in "quit" +(define (read-loop-i) + + + ;(semaphore-wait fair) + (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (begin (kill-thread a) + (kill-thread t)))) + (display (string-append output-prompt input "\n")) + ;(semaphore-post fair) + (read-loop-i) + ) + + +;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port +(define (hello-world) + (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms + ;; with server + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + ;; at this time we simulate the input from different users + (define what-to-print (random-integer 0 2)) + (if (= what-to-print 0) + (display "Doug: What's up, up?\n") + (display "Fred: Looking good, good!\n")) + ;(semaphore-post fair) + (hello-world)) + +(define t (thread (lambda () + (read-loop-i)))) +(define a (thread (lambda () + (hello-world)))) + +(thread-wait t) ;; returns prompt back to drracket +;; below doesn't execute +; (sleep 10) +; (kill-thread t) +; (define a (thread (display "hello world!\n"))) +; (display "John: hello soso\n") +; (display "Emmanuel: cumbaya!!!!\n") diff --git a/tests/tcpevents/server.rkt b/tests/tcpevents/server.rkt new file mode 100644 index 0000000..4313bda --- /dev/null +++ b/tests/tcpevents/server.rkt @@ -0,0 +1,39 @@ +#lang racket + +(define (serve in-port out-port) + (let loop [] + (define evt (sync/timeout 2 + (read-line-evt in-port 'any) + (thread-receive-evt))) + (cond + [(not evt) + (displayln "Timed out, exiting") + (tcp-abandon-port in-port) + (tcp-abandon-port out-port)] + [(string? evt) + (fprintf out-port "~a~n" evt) + (flush-output out-port) + (loop)] + [else + (printf "Received a message in mailbox: ~a~n" + (thread-receive)) + (loop)]))) + +(define port-num 4321) +(define (start-server) + (define listener (tcp-listen port-num)) + (thread + (lambda () + (define-values [in-port out-port] (tcp-accept listener)) + (serve in-port out-port)))) + +(start-server) + +(define client-thread + (thread + (lambda () + (define-values [in-port out-port] (tcp-connect "localhost" port-num)) + (display "first\nsecond\nthird\n" out-port) + (flush-output out-port) + ; copy-port will block until EOF is read from in-port + (copy-port in-port (current-output-port))))) diff --git a/tests/tcpvanilla/README.md b/tests/tcpvanilla/README.md new file mode 100644 index 0000000..b8e2883 --- /dev/null +++ b/tests/tcpvanilla/README.md @@ -0,0 +1,20 @@ +a simple experiment on communication via tcp ports + +a server runs continously servicing clients. Clients connect, send a message, and +server replies with a message. Message should appear in each separate REPL area +prompt + +run server.rkt in a REPL +``` +,en server.rkt +(define stop (serve 8080)) ;; starts serve listening at port 8080 +(stop) ;; to stop server and free the ports + +``` + +run client.rkt in a separate REPL +``` +,en client.rkt +(define stop (client 8080)) ;; starts client talking to server at port 8080 + +``` diff --git a/tests/tcpvanilla/client.rkt b/tests/tcpvanilla/client.rkt new file mode 100644 index 0000000..967d2b9 --- /dev/null +++ b/tests/tcpvanilla/client.rkt @@ -0,0 +1,72 @@ +#lang racket + +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (client 8080)) +;; use your web browser to connect localhost:8080 greeted with "hello world" +;; (stop) to close the server + +(define (client port-no) + (define main-client-cust (make-custodian)) + (parameterize ([current-custodian main-client-cust]) + ;; connect to server at port 8080 + (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values + ;; binds to multiple values akin to unpacking tuples in python + ; (thread (lambda () + (chat in out) + (close-input-port in) + (close-output-port out)) + (custodian-shutdown-all main-client-cust)) + + ; (sleep 60) ;; run for 3 minutes then close + ; (define (loop) + ; (write (read-line (current-input-port)) out) + ; (flush-output out) + ; (write (read-line in) (current-output-port)) + ; (define listener (tcp-listen port-no 5 #t)) + ; (define (loop) + ; (accept-and-handle listener) + ; (loop)) + ; (thread loop))) + ; (custodian-shutdown-all main-client-cust) + #| (lambda () |# + ; (displayln "Goodbye, shutting down client\n") + #| (custodian-shutdown-all main-client-cust)) |# + +(define (chat in out) + ; (driver-loop in out) + (writeln "Ibrahim: Hello, anyone in chat?" out) + (flush-output out) ;; ports are buffered in racket must flush or you + ;; will read #eof + (sleep 10) ;; wait 10 seconds + (define serv-message (read-line in)) + (displayln serv-message) ;; read the servers replay message which is original + ;; with echo appended to it + ) + +; (define input-prompt "Hermes: ") + +(define (driver-loop in out) + ; (prompt-for-input input-prompt) + (display ">>> ") + (define input (read)) + (writeln (string-append "Ibrahim: " input) out) + (flush-output out) + ; (sleep 10) + (define output (read-line in)) + (displayln output) + (driver-loop in out)) + + +#| (let ((input (read))) |# +; ) +; (let ((input (read))) +; (let ((output (mc-eval input the-global-environment))) +; (announce-output output-prompt) +; (user-print output))) +; (driver-loop)) +; +; (define (announce-output string) +; (display string)) +#| |# diff --git a/tests/tcpvanilla/client2.rkt b/tests/tcpvanilla/client2.rkt new file mode 100644 index 0000000..47e3052 --- /dev/null +++ b/tests/tcpvanilla/client2.rkt @@ -0,0 +1,43 @@ +#lang racket + +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (client 8080)) +;; use your web browser to connect localhost:8080 greeted with "hello world" +;; (stop) to close the server + +(define (client port-no) + (define main-client-cust (make-custodian)) + (parameterize ([current-custodian main-client-cust]) + ;; connect to server at port 8080 + (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values + ;; binds to multiple values akin to unpacking tuples in python + (thread (lambda () + (send-message in out) + (close-input-port in) + (close-output-port out)))) + (sleep 20) + ; (define (loop) + ; (write (read-line (current-input-port)) out) + ; (flush-output out) + ; (write (read-line in) (current-output-port)) + ; (define listener (tcp-listen port-no 5 #t)) + ; (define (loop) + ; (accept-and-handle listener) + ; (loop)) + ; (thread loop))) + (custodian-shutdown-all main-client-cust) + #| (lambda () |# + ; (displayln "Goodbye, shutting down client\n") + #| (custodian-shutdown-all main-client-cust)) |#) + +(define (send-message input-port output-port) + (writeln "Doug: Hello, how's it going?" output-port) + (flush-output output-port) ;; ports are buffered in racket must flush or you + ;; will read #eof + (sleep 10) ;; wait 10 seconds + (define serv-message (read-line input-port)) + (displayln serv-message) ;; read the servers replay message which is original + ;; with echo appended to it + ) diff --git a/tests/tcpvanilla/server.rkt b/tests/tcpvanilla/server.rkt new file mode 100644 index 0000000..bf72aff --- /dev/null +++ b/tests/tcpvanilla/server.rkt @@ -0,0 +1,58 @@ +#lang racket + +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (serve 8080)) +;; use your web browser to connect localhost:8080 greeted with "hello world" +;; (stop) to close the server + +(define (serve port-no) + (define main-cust (make-custodian)) + (parameterize ([current-custodian main-cust]) + (define listener (tcp-listen port-no 5 #t)) + (define (loop) + (accept-and-handle listener) + (loop)) + (thread loop)) + (lambda () + (displayln "\nGoodbye, shutting down all services\n") + (custodian-shutdown-all main-cust))) + +(define (accept-and-handle listener) + (define cust (make-custodian)) + (parameterize ([current-custodian cust]) + (define-values (in out) (tcp-accept listener)) + (thread (lambda () + (handle in out) ;; this handles connection with that specific client + (close-input-port in) + (close-output-port out)))) + ;; Watcher thread: + (thread (lambda () + (sleep 120) + (custodian-shutdown-all cust)))) + +(define (handle in out) + ; (server-loop in out) + (sleep 5) ;; wait 5 seconds to guarantee client has already send message + (define echo (read-line in)) ;; bind message to echo + (displayln (string-append echo "\n")) + ; echo back the message, appending echo + ; could regex match the input to extract the name + (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back + (flush-output out) +) + +(define input-prompt "Hermes: ") + +(define (server-loop in out) + (define echo (read-line in)) + (displayln echo) + (display ">>> ") + + (define input (read)) + (writeln (string-append "Admin: " input) out) + (flush-output out) + ; (sleep 10) + (server-loop in out)) + diff --git a/tests/tcpvanilla/tcptalk.rkt b/tests/tcpvanilla/tcptalk.rkt new file mode 100644 index 0000000..d069851 --- /dev/null +++ b/tests/tcpvanilla/tcptalk.rkt @@ -0,0 +1,30 @@ +#lang racket + +(define listener (tcp-listen 8083 5 #t)) ;; listener to service connection requests +;; client attempts to connect. Receives an input and output port +(define-values (client-in client-out) (tcp-connect "localhost" 8083)) +;; server accepts the connection request. Also gets a pair of ports +(define-values (server-in server-out) (tcp-accept listener)) + +;; client sends identifying message +(display (string-append "Client:My name is " "Ibrahim" "\n") + client-out) +(flush-output client-out) ;; must flush as ports are buffered in racket + +;; server receives and reads it +;; cooler if on separate racket instances +(read-line server-in) ;; --> "Client:My name is #hostname. +;; server replies +(display (string-append "Server:Hi " "Ibrahim" "\n") server-out) +(flush-output server-out) ;; flush flush + +;; client displays server message +(read-line client-in) +(close-output-port server-out) +(close-output-port client-out) +(read-line client-in) ;; --> eof object #eof +(read-line server-in) ;; --> eof object #eof +(tcp-close listener) +; (custodian-shutdown-all (current-custodian)) ;; release all resources including + ;; tcp, file, custom ports + ;; application exits -- cgit v1.2.3 From 44c715c55c239495da8f780276866c0041f04139 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 22:46:18 -0400 Subject: final polish for release for 0.2 --- Hermes/concurrentreadandprint.rkt | 8 +++----- Hermes/tcpcommunication.rkt | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Hermes/concurrentreadandprint.rkt b/Hermes/concurrentreadandprint.rkt index f67f1dd..95d02c1 100644 --- a/Hermes/concurrentreadandprint.rkt +++ b/Hermes/concurrentreadandprint.rkt @@ -1,12 +1,10 @@ #lang racket (require math/base) ;; for random number generation +;; a proof of concept +;; one thread waits for input +;; another displays messages in the background -;; author: Ibrahim Mkusa -;; about: print and read concurrently -;; notes: output may need to be aligned and formatted nicely -;; look into -;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 ;; create custodian for managing all resources ;; so we can shutdown everything at once diff --git a/Hermes/tcpcommunication.rkt b/Hermes/tcpcommunication.rkt index 27a5151..134e697 100644 --- a/Hermes/tcpcommunication.rkt +++ b/Hermes/tcpcommunication.rkt @@ -1,4 +1,7 @@ #lang racket +;; Reads input iteratively then sends it to local server +;; client reads back the message and displays it + (require math/base) ;; for random number generation (define listener (tcp-listen 4326 5 #t)) -- cgit v1.2.3