in last 10 minutes
ALR - ćw - temat C
Materiały o j. TclGniazdka i programowanie zdarzeniowe w j. Tcl
Prosty sposób na implementowanie algorytmów asynchronicznych w realnym świecie...
Przychodzące komunikaty są obsługiwane przez "handler zdarzeń" (stąd programowanie zdarzeniowe).
Jak to się ma do teoretycznego modelu obliczeń?
program (interp tcl-a) = węzeł grafu kom,
połączenie TCP = krawędź grafu kom,
wykonanie handlera = zdarzenie obliczeniowe.
## klient
#
set host "localhost"
set s [socket $host 10000]
# tworzymy połączenie tcp z serwerem na maszynie $host, port=10000
# komenda socket zwraca gniazdko repr. koniec tego połączenia
puts $s "A ku ku !!!"
# wysylamy dane przez gniazdko s
flush $s
# flush to wypróżnienie buforów
# !!! bardzo ważne bez tego dane nie zostaną "wypchnięte" !!!
close $s
## serwer # socket -server obsluga 10000 proc obsluga {s args} { fileevent $s readable "obslugaKli $s" # dla każdego zgłaszającego się klienta definiujemy # obsługę zdarzenia "readable" na gniazdku tego klienta ... # uwaga: jeśli można odczytać 1 znak to można odczytać cały komunikat! } proc obslugaKli s { if {[eof $s]} { close $s; return } # "eof" pojawi się dokładnie wtedy, gdy klient zamknie gniazdko! # wtedy po stronie serwera usuwamy zasoby związane z tym klientem set linia [gets $s] puts $s "odp na: $linia" flush $s } # wersja obslugaKli z tzw. "zmiennymi sesyjnymi" proc obslugaKli s { upvar ::dane,$s dane; # tabl. dane to zm. sesyjne... if {[eof $s]} { close $s; unset -nocomplain dane; return } # zm. sesyjne są automatycznie usuwane, gdy klient się odłączy set linia [gets $s] lappend dane(linie) $linia; # np. zapamiętujemy linie, które przysłano puts $s "odp na: $linia" flush $s }
Objaśnienie operacji I/O w j. Tcl:
Tcl_io_tutorial
patrz też Tcl_net_idioms (uwagi praktyczne o budowaniu serwerów zdarzeniowych w j. Tcl)
Jak programować algorytmy asynchroniczne/zdarzeniowe w praktyce? (w j. Tcl)
"Handler" to procedura obsługująca przychodzące komunikaty/ zdarzenia.Większe problemy (programistyczne) zaczynają się, gdy handler musi czekać na inne komunikaty.
Możliwe rozwiązania:
1. tylko handler
- jeśli handler potrzebuje innego komunikatu to musimy go rozbić na dwa...
- niskopoziomowe programowanie! (klasyczna maszyna stanowa)
- handler (proc) zawsze wykonuje się w 100%, tj od początku do końca
2. handler + vwait
- handler czeka na inny komunikat przy pomocy "vwait zmienna"
- nie można zagnieżdżać vwait-ów/ pętli zdarzeń !!! (...)
3. handler w wątku/fiberze/coroutinie
- gdy handler czeka na komunikat to robi yield (usypia się) i jest budzony gdy ten komunikat się pojawi
- to jest najogólniejsze rozwiązanie...
Zadanie 40 (inż.)(2.5pkt) "czat audio"
Chodzi o możliwość przekazywania strumienia audio między użytkownikami
w trybie halfduplex (tzn jeden nadaje - wielu słucha).
Obsługę dzwięku dostarcza pakiet "snack", jednak w tym zadaniu nie trzeba go używać;
chodzi tylko o to aby zapewnić, że w danej chwili "jeden nadaje a wielu słucha",
przy czym WYMAGA się aby cały czas była spełniona "zasada X":
jeśli istnieje słuchający to musi istnieć nadający.
(zasada ta wynika ze specyficznych cech pakietu snack...)
Oprogramowanie klienta powinno zawierać guzik "chcę nadawać",
który jest zielony gdy możemy mówić i czerwony gdy słuchamy...
Wymyśl sposób na sprawdzenie czy Twoje rozwiązanie jest poprawne!
np. "log" z zapisem zmiany stanu klientów, z b. dokładnym czasem zdarzenia,
tworzony przez klientów, plus skrypt sprawdzający czy wszystko ok ?!?!
Zadanie 40a (inż.)(1.5pkt) "czat audio (błędny)"
Pokaż, że Twój sposób sprawdzania poprawności z.40
wykaże błąd w błędnym rozwiązaniu...
Zadanie 40b (inż.)(1.5pkt) "send/recv dla j. Tcl (lub innego)"
Zaprogramuj prawidłowe proc do wysyłania/odbierania komunikatów,
proc send {sock msg} {...}
proc recv {sock} {...}
które będą działały poprawnie w następujących warunkach:
1 wątek, 1 konsola, tryb nieblokujący w obu proc,
dowolnie długie komunikaty z dowolnymi znakami,
odporność na ataki przez fałszywy format komunikatu,
brak ryzyka zakleszczenia...
Oprócz proc należy podać przykład ich zastosowania, jak w przykładach wyżej,
w szczególności sprawdzić czy przy długich kom jest ok...
Opisać także format komunikatu używany przez proc.
Messaging, MOM, "ZeroMQ", ...
MOM = Message Oriented Middleware
Inne niż ZeroMQ oprogramowanie/prot typu MOM:
RabbitMQ, qpid, AMQP, JMS (Java), stomp, Kafka, ActiveMQ, MQTT, ...
ZeroMQ (zeromq.org) to biblioteka typu "super gniazda" ...
książka: zguide.zeromq.org (zguide),
spec: dokumenty RFC,
api docs:
api.zeromq.org/4-1,
api.zeromq.org/3-0,
api.zeromq.org/2-0
(widać różnice między wersjami!)
Uwagi o ZeroMQ (ZMQ):
- komunikacja i sposób serializowania str. danych są całkowicie rozdzielone,
można serializować textowo i binarnie na różne sposoby...
ser. txt. : XML (wiele std.; SOAP, JAXB), JSON, YAML, ...
ser. bin. : msgpack, protobuf (google?), thrift, CDR z Corby, ... - istnieje wiele wzorców komunikacji, np. REQ/REP, PUB/SUB, ...
zmq wymusza prawidłowe posługiwanie sie met. send/recv w danym wzorcu!
niektóre wzorce pozwalają na wysyłanie do wielu odbiorców (subskrybentów) - gniazdko ZMQ może mieć wiele połączeń!
tzn. można wielokrotnie wywołać met. connect na tym samym gniazdku! (zastosowania? patrz niżej)
tradycjne gniazda (BSD) maja tylko 1 połączenie, dlatego na serewerze jest ich wiele... - komunikaty mogą być wieloczęściowe!
w niektórych częściach umieszcza się "dane techniczne" np. adr. nadawcy
- gniazdko ZMQ ma typ: REQ, REP, ROUTER, DEALER, ...
typ określa jak działają metody send/recv na tym gniazdku;
niekiedy metody te dodają/usuwają części komuniktu (jakby nagłówki);
jak działaja gniazdka typu ROUTER? patrz zguide, chapter 3;
w manualu zmq_socket() jest krótki opis wszystkich typów gniazdek... - są dwa zasadnicze wzorce komunikacyjne: REQ/REP i PUB/SUB,
REQ/REP coś jak RPC, klient wysyła pytanie, serwer je odbiera, wysyła odp, klient odbiera odp;
PUB/SUB działa jak "multicasting"; pub wysyła komunikat do wszystkich sub (subskrybentów);
subskrybenci muszą podać "temat" ktory ich interesuje (jest to prefix komunikatu!),
temat moze być też w pierwszej części wieloczęsciowego komunikatu! - jeśli gniazdko REQ klienta jest podłączone do wielu gniazdek REP serwerów,
to komunikaty jest wysyłany cyklicznie do kolejnych serwerów (RoundRobin),
jest to prymitywna metoda zapewniania load balancing-u... - oba wz. kom. REQ/REP i PUB/SUB występuja też w wersji z "proxy";
REQ/ROUTER+DEALER/REP, proxy zawiera 2 gniazdka o typach ROUTER i DEALER
PUB/XSUB+XPUB/SUB, proxy zawiera 2 gniazdka o typach XSUB i XPUB;
usługę proxy można realizować jedną komendą "zmq proxy s_we s_wy" (w impl. tcl-owej ZMQ) - inne wz. kom.: PUSH/PULL, ???, ...
Oprogramowanie ZeroMQ oraz przykłady w j. Tcl:
zeromq.zip
(z sodium)
zawiera pkg tcl-a (lin32), wymaga tcl8.6,
folder z przykładami
PRZED uruchomieniem konsoli uruchomić skrypt ". ./e" !!
docs dla tcl/zmq: zmq w tcl (wiki),
msgpack w tcl (serializacja binarna), slajdy pomocnicze
## ZeroMQ - serwer, wzorzec REQ/REP # lappend auto_path ./zeromq package re zmq #% 4.0.1 package re msgpack #% 0.5.0 zmq context c1 zmq socket s1 c1 REP #% ::s1 s1 bind "tcp://*:7777" s1 readable qqq # + callback serwerowy, automatycznie odp. klientom... proc qqq args { set x [s1 recv] puts "args=$args, x=$x" s1 send "odp na: $x"; # odp jest niezbedna w REP/REQ ! } vwait qqq s1 destroy c1 destroy ## ZeroMQ - klient, wzorzec REQ/REP # lappend auto_path ./zeromq package re zmq #% 4.0.1 package re msgpack #% 0.5.0 zmq context c1 zmq socket s1 c1 REQ #% ::s1 s1 connect "tcp://localhost:7777" s1 send "A ku ku !!! ???" s1 recv #% odp na: A ku ku !!! ??? # + zmq WYMUSZA odp. kolejnosc send/recv # zgodna ze wzorcem komunikacjyjnym (REQ/REP w tym przypadku) c1 config s1 config # + introspekcja? s1 destroy c1 destroy
Uwaga, 14.06.2021: w zadaniach o ZMQ można używać innej nakładki na bibl zmq, niż tcl-owa...
Zadanie 41a "eksperyment z ZeroMQ w j. Tcl, wzorce komunikacyjne"Proszę rozbudować powyższy przykład, tak aby przetestować
TRZY różne wzorce komunikacyjne (nie tylko REQ/REP, patrz docs...).
Proszę także opisać własnymi słowami działanie każdego z wzorców komunikacyjnych!
Zadanie 41b "eksperyment z ZeroMQ w j. Tcl i innych"
Proszę rozbudować powyższy przykład, tak aby:
1. były używane 2 różne języki programowania (Tcl + jakiś inny),
2. powinny współpracować programy w różnych j. prog.
Zadanie 42 "ZeroMQ + serializacja BINARNA"
Stworzyć przykład z wzorcem REQ/REP bibl. ZeroMQ, w którym przesyła się
zbiór (dowolnej mocy) macierzy oznaczonych przez etykiety txt,
macierze mają dowolne wymiary;
dane maja być serializowane binarnie;
serwer powinien zwrócic macierze przemnożone przez stały współczynnik.
Propozycja (kontrowersyjna): do serializacji binarnej użyć CDR z Corby;
w plikach "cdr*.tcl" w tym folderze są przykłady jak wyciągnąć CDR z
Combata (broker Corby j. Tcl) i JavaIDL (broker Corby j. Java).
10.05.2021: Combat działa jedynie z tclkit8.6b1 (z uwagi na wersje Itcl 3.0)
Zadanie 43 "ZeroMQ + proxy"
Zbuduj przykład używający procesu proxy do którego podłączają się
zarówno klienci jak i serwery.
Użyj gniazdek REQ dla klientów, REP dla serwerów, ROUTER|DEALER dla proxy.
W takim układzie żądania klientów będą "równomiernie rozkładane" pośród serwerów.
Na 1 żądanie klienta przypada jedna odpowiedź od serwera (który został wybrany do obsługi tego klienta).
Zadanie 44 (1.5pkt) "ZeroMQ + proxy, inny wzorzec komunikacji"
Zrób to samo co w zadaniu poprzednim, z tą różnicą, że:
na 1 żądanie klienta przypada wiele (nie wiadomo ile) odpowiedzi serwera;
ostatnia odpowiedź jest specjalnie oznaczona;
Wskazówka: Da się to zrobić przy pomocy gniazdek DEALER/ROUTER,
oraz drobnych modyfikacji komunikatów, czytaj chapter 3 i zmq_socket()
Zadanie 45 "ZeroMQ + security"
Zbadaj jak działają zabezpieczenia typu "PLAIN" w ZMQ, analizując przykłady alr_zmq03* z folderu,
oraz dokumentację w nich zawartą (w alr_zmq03kli.tcl); patrz także api doc...
Opisz własnymi słowami jak to wszystko działa,
oraz jak klient może się przekonać, że podał złe hasło(!).
Zadanie 46 (1.5pkt) "ZeroMQ + security c.d."
Zbuduj przykład podobny do tego z poprzedniego zadania,
ale tym razem dla mechanizmu "CURVE" (wymaga wersji zmq z sodium !!).
Ten mechanizm umożliwia szyfrowanie kom. a każdy węzeł ma parę kluczy (pub/priv).
Klucze pub pozwalają uwierzytelniać przeciwną stronę.
Wskazówki: Jak się konfiguruje ten mechanizm?? Patrz dokumenty i blogi z alr_zmq03kli.tcl,
w szczególności blog 45 (The ZeroMQ Security API) oraz zmq_curve.
Nie wiadomo jak są zakodowane "credentials" w proc www na ser (kodowanie z85 ?) - zbadaj to.
Sprawdź programem wireshark czy komunikaty rzeczywiście są zaszyfrowane - wklej dowód.
Zbadaj co się dzieje jeśli podać wadliwe klucze - opisz efekty.
Zbadaj co się dzieje jeśli klucze są ok, ale kli został odrzucony przez ser (proc www na ser).
Zadanie 46a "ZeroMQ + security vs proxy"
Zbadaj czy bezpieczne połączenie (patrz Z.46) możę przechodzić przez proxy,
np. REQ -> ROUTER|DEALER -> REP, gdzie ser REP uwierzytelnia kli REQ
Zadanie 47 "ZeroMQ + REQ/REP vs kill"
Mamy gniazdko s1 typu REQ podłączone do 3 gniazdek REP, w 3 osobnych procesach;
wykonujemy operacje: s1 send "a ku ku"; s1 recv
w odp powinien być nr portu i pid procesu/serwera z gniazdkiem REP;
co się stanie jeśli zabić jeden z serwerów?
jeśli jest problem (blokada?) to jak temu przeciwdziałać?
wymień wszystkie możliwości, m.in związane z poll i zamianą REQ na coś innego;
weź też pod uwagę restartowanie serwera z tym samym nr portu...
Zadanie 47a "ZeroMQ + PUB/SUB vs kill"
odpowiednik zadania 47, ale dla wzorca komunikacyjnego PUB/SUB
Zadanie 48 (1.5pkt) "ZeroMQ + gubienie pakietów"
Zbadaj kiedy ZMQ gubi pakiety; przeanalizuj następujące "architektury":
1. PUSH -> PULL,
2. PUB -> SUB,
3. PUB -> XSUB|XPUB -> SUB;
Wymyśl sposób na obronę przed tym zjawiskiem w przypadku (2) i (3).
Wskazówka: zajrzyj do odp rozdziału zguide...;
Potrzebne pojęcia: HWM = High Water Mark (param config socketu)