diff options
-rw-r--r-- | Hermes/client.rkt | 102 | ||||
-rw-r--r-- | Hermes/concurrentreadandprint.rkt | 75 | ||||
-rw-r--r-- | Hermes/server.rkt | 140 | ||||
-rw-r--r-- | Hermes/tcpcommunication.rkt | 60 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | docs/FP4-instructions.md (renamed from FP4-instructions.md) | 0 | ||||
-rw-r--r-- | ext/arch_diagram.png (renamed from arch_diagram.png) | bin | 23853 -> 23853 bytes | |||
-rw-r--r-- | ext/architecture_diagram.png (renamed from architecture_diagram.png) | bin | 65212 -> 65212 bytes | |||
-rw-r--r-- | tests/gui/Gui_Exploration.rkt (renamed from Gui_Exploration.rkt) | 0 | ||||
-rw-r--r-- | tests/gui/windows.rkt (renamed from feasibility_analysis/gui/windows.rkt) | 0 | ||||
-rw-r--r-- | tests/gui/windows2.rkt (renamed from feasibility_analysis/gui/windows2.rkt) | 0 | ||||
-rw-r--r-- | tests/tcpevents/README.md (renamed from feasibility_analysis/tcpevents/README.md) | 0 | ||||
-rw-r--r-- | tests/tcpevents/crpovertcp.rkt | 155 | ||||
-rw-r--r-- | tests/tcpevents/server.rkt (renamed from feasibility_analysis/tcpevents/server.rkt) | 0 | ||||
-rw-r--r-- | tests/tcpvanilla/README.md (renamed from feasibility_analysis/tcpvanilla/README.md) | 0 | ||||
-rw-r--r-- | tests/tcpvanilla/client.rkt (renamed from feasibility_analysis/tcpvanilla/client.rkt) | 0 | ||||
-rw-r--r-- | tests/tcpvanilla/client2.rkt (renamed from feasibility_analysis/tcpvanilla/client2.rkt) | 0 | ||||
-rw-r--r-- | tests/tcpvanilla/server.rkt (renamed from feasibility_analysis/tcpvanilla/server.rkt) | 0 | ||||
-rw-r--r-- | tests/tcpvanilla/tcptalk.rkt (renamed from feasibility_analysis/tcpvanilla/tcptalk.rkt) | 0 |
20 files changed, 537 insertions, 2 deletions
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..95d02c1 --- /dev/null +++ b/Hermes/concurrentreadandprint.rkt @@ -0,0 +1,75 @@ +#lang racket +(require math/base) ;; for random number generation + +;; a proof of concept +;; one thread waits for input +;; another displays messages in the background + + +;; 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..134e697 --- /dev/null +++ b/Hermes/tcpcommunication.rkt @@ -0,0 +1,60 @@ +#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)) +(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/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 *~ @@ -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/FP4-instructions.md b/docs/FP4-instructions.md index 6a04e91..6a04e91 100644 --- a/FP4-instructions.md +++ b/docs/FP4-instructions.md diff --git a/arch_diagram.png b/ext/arch_diagram.png Binary files differindex 6bb8803..6bb8803 100644 --- a/arch_diagram.png +++ b/ext/arch_diagram.png diff --git a/architecture_diagram.png b/ext/architecture_diagram.png Binary files differindex 1949ae0..1949ae0 100644 --- a/architecture_diagram.png +++ b/ext/architecture_diagram.png diff --git a/Gui_Exploration.rkt b/tests/gui/Gui_Exploration.rkt index ff4d2d3..ff4d2d3 100644 --- a/Gui_Exploration.rkt +++ b/tests/gui/Gui_Exploration.rkt diff --git a/feasibility_analysis/gui/windows.rkt b/tests/gui/windows.rkt index 4524673..4524673 100644 --- a/feasibility_analysis/gui/windows.rkt +++ b/tests/gui/windows.rkt diff --git a/feasibility_analysis/gui/windows2.rkt b/tests/gui/windows2.rkt index 3f60c80..3f60c80 100644 --- a/feasibility_analysis/gui/windows2.rkt +++ b/tests/gui/windows2.rkt diff --git a/feasibility_analysis/tcpevents/README.md b/tests/tcpevents/README.md index 7c3ec21..7c3ec21 100644 --- a/feasibility_analysis/tcpevents/README.md +++ b/tests/tcpevents/README.md 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/feasibility_analysis/tcpevents/server.rkt b/tests/tcpevents/server.rkt index 4313bda..4313bda 100644 --- a/feasibility_analysis/tcpevents/server.rkt +++ b/tests/tcpevents/server.rkt diff --git a/feasibility_analysis/tcpvanilla/README.md b/tests/tcpvanilla/README.md index b8e2883..b8e2883 100644 --- a/feasibility_analysis/tcpvanilla/README.md +++ b/tests/tcpvanilla/README.md diff --git a/feasibility_analysis/tcpvanilla/client.rkt b/tests/tcpvanilla/client.rkt index 967d2b9..967d2b9 100644 --- a/feasibility_analysis/tcpvanilla/client.rkt +++ b/tests/tcpvanilla/client.rkt diff --git a/feasibility_analysis/tcpvanilla/client2.rkt b/tests/tcpvanilla/client2.rkt index 47e3052..47e3052 100644 --- a/feasibility_analysis/tcpvanilla/client2.rkt +++ b/tests/tcpvanilla/client2.rkt diff --git a/feasibility_analysis/tcpvanilla/server.rkt b/tests/tcpvanilla/server.rkt index bf72aff..bf72aff 100644 --- a/feasibility_analysis/tcpvanilla/server.rkt +++ b/tests/tcpvanilla/server.rkt diff --git a/feasibility_analysis/tcpvanilla/tcptalk.rkt b/tests/tcpvanilla/tcptalk.rkt index d069851..d069851 100644 --- a/feasibility_analysis/tcpvanilla/tcptalk.rkt +++ b/tests/tcpvanilla/tcptalk.rkt |