Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

pl:prolog:prolog_lab:prolog_lab_http [2009/05/20 10:37]
piw09 Brakowało nawiasu zamykającego w linii zaczynającej się od :- use_module
pl:prolog:prolog_lab:prolog_lab_http [2019/06/27 15:50]
Linia 1: Linia 1:
-====== LAB: Integracja z HTTP/WWW ====== 
- 
-Celem laboratorium jest ukazanie podstawowych metod integracji języka Prolog z protokołem HTTP, używania gniazd TCP oraz zademonstrowanie wielowątkowości w SWI-Prolog. 
- 
-===== -. Wątki ===== 
- 
-Wielowątkowość w SWI-Prolog oparta jest na standardzie POSIX. 
- 
-Dokumentacja:​ [[http://​www.swi-prolog.org/​pldoc/​doc_for?​object=section(1%2c%20%278%27%2c%20swi(%27%2fdoc%2fManual%2fthreads.html%27))|Multi-threaded applications]] 
- 
-==== Tworzenie wątków ==== 
- 
-Tworzenie oddzielnego wątku odbywa się przy użyciu predykatu thread_create/​3:​ 
-<code prolog> 
-thread_create(:​Goal,​ -Id, +Options) 
-</​code>​ 
- 
-Predykat //​thread_self/​1//​ zwraca identyfikator wątku, w którym został wywołany. 
- 
-**Ćwiczenie:​** 
- 
-Proszę wkleić poniższy kod do pliku i wczytać go w SWI-Prolog: 
-<code prolog> 
-start :- 
- thread_create(write_ID(10),​ID1,​[]),​ 
- write('​Thread with ID: '), write(ID1), writeln('​ has been started!'​),​ 
- thread_create(write_ID(10),​ID2,​[]),​ 
- write('​Thread with ID: '), write(ID2), writeln('​ has been started!'​). 
- 
-write_ID(0). 
- 
-write_ID(Times) :- 
- thread_self(ID),​ 
- write(ID), 
- NewTimes is Times - 1, 
- write_ID(NewTimes). 
-</​code>​ 
- 
-Proszę uruchomić program predykatem //start/0// kilkakrotnie i zaobserwować działanie. 
- 
-==== Synchronizacja wątków ==== 
- 
-SWI-Prolog implementuje semafor, który można wykorzystać do kontroli sekcji krytycznej - mutex (MUTual EXclusive device). Proszę zapoznać się z predykatami:​ [[http://​www.swi-prolog.org/​pldoc/​man?​predicate=mutex_lock%2f1|mutex_lock/​1]] i [[http://​www.swi-prolog.org/​pldoc/​man?​predicate=mutex_unlock%2f1|mutex_unlock/​1]]. 
- 
-**Ćwiczenie** 
- 
-Kod programu z poprzedniego ćwiczenia proszę zmodyfikować tak, aby zaobserwować niepożądany efekt korzystania z jednego zasobu przez więcej niż jeden wątek jednocześnie. Druga klauzula predykatu //​write_ID/​1//​ mogłaby wyglądać np. tak: 
-<code prolog> 
-write_ID(Times) :- 
- thread_self(ID),​ 
- write(ID), write(':​ I am running! '), 
- NewTimes is Times - 1, 
- write_ID(NewTimes). 
-</​code>​ 
- 
-Proszę przetestować,​ czy zamierzony efekt zachodzi, a następnie tak zmodyfikować program, aby komunikaty jednego wątku (np. //2: I am running!//) nie przeplatały się z komunikatami drugiego. 
- 
-==== Komunikacja między wątkami ==== 
- 
-Każdy wątek ma przypisaną kolejkę wiadomości,​ z której może odczytywać wiadomości wysyłane przez inne wątki w postaci termu. 
- 
-//​thread_send_message(+ThreadId,​ +Term)// - wysyła wiadomość w postaci termu do kolejki wiadomości wskazanego wątku. 
- 
-//​thread_get_message(?​Term)//​ - czeka na wiadomość w kolejce, która będzie mogła być zunifikowana z termem //Term//. 
- 
-//​threads/​0//​ - podaje informacje o pracujących/​zakończonych wątkach i status każdego z nich. 
- 
-**Ćwiczenie** 
- 
-Proszę wkleić poniższy kod do pliku i wczytać go w SWI-Prolog: 
-<code prolog> 
-start :- 
- thread_create(do_nothing,​ID1,​[]),​ 
- write('​Thread with ID: '), write(ID1), writeln('​ has been started!'​),​ 
- thread_create(do_nothing,​ID2,​[]),​ 
- write('​Thread with ID: '), write(ID2), writeln('​ has been started!'​). 
- 
-do_nothing :- 
- thread_self(ID),​ 
- thread_get_message(say(A)),​ 
- write('​Thread '), write(ID), write('​ says: '), writeln(A). 
-</​code>​ 
- 
-Po użyciu predykatu //start/0// dwa wątki pracują i czekają na wiadomość w postaci termu //say/1//. 
- 
-Proszę użyć predykatu //​threads/​0//​ i zauważyć, że główny wątek (ten, w którym wpisuje się polecenia w konsoli) także jest wylistowany i zachowuje się jak inne wątki (można mu wysłać wiadomość,​ można go synchronizować z innymi, itp.). 
- 
-Proszę wpisać w konsoli: thread_send_message(ID,​say('​Something stupid!'​)),​ gdzie ID to identyfikator jednego z pracujących wątków. Po ponownym użyciu predykatu //​threads/​0//​ proszę zauważyć, że jeden z wątków zmienił status. Został zakończony sukcesem (//true//). Proszę wysłać wiadomość także do drugiego oczekującego wątku. 
- 
-==== Problem pięciu filozofów ==== 
- 
-Proszę zapoznać się z [[http://​pl.wikipedia.org/​wiki/​Problem_ucztuj%C4%85cych_filozof%C3%B3w|problemem pięciu filozofów w Wikipedii]]. To klasyczny problem, którego rozwiązanie korzysta z wielowątkowości i synchronizacji wątków. Proszę wczytać plik {{5_philosophers.pl}},​ zapoznać się z nim i uruchomić predykatem //​start/​0//​. W początkowej części programu znajdują się ustawienia. Proszę je zmodyfikować wg własnego uznania i przetestować poprawność działania programu. 
- 
- 
-===== -. Gniazda TCP ===== 
- 
-Biblioteka //socket// udostępnia w SWI-Prolog obsługę gniazd TCP po stronie klienta i serwera. 
- 
-Istotne predykaty: 
-  * //​tcp_socket(-SocketId)//​ inicjalizuje gniazdo i unifikuje jego identyfikator ze zmienną logiczna //​SocketId//,​ 
-  * //​tcp_connect(+Socket,​+Host:​+Port)//​ dokonuje połączenia z hostem na wskazanym porcie przy użyciu uprzednio zainicjowanego gniazda, 
-  * //​tcp_open_socket(+SocketId,​-InStream,​-OutStream)//​ otwiera dwa strumienie (wejścia i wyjścia) SWI-Prolog dla gniazda, 
-  * //​tcp_accept(+Socket,​-Slave,​-Peer)//​ działa po stronie serwera, oczekuje na połączenie ze strony klienta, tworzy nowe gniazdo dla klienta o identyfikatorze //Slave//, zmienna logiczna //Peer// jest unifikowana z adresem IP klienta. 
-  * //​tcp_close_socket(+SocketId)//​ zamyka gniazdo. Ten sam efekt można uzyskać zamykając strumienie gniazda predykatem //​close/​1//​. 
- 
-**__UWAGA!__ W poniższych ćwiczeniach z użyciem gniazd TCP proszę używać portów z zakresu 33700-33999.** 
- 
-==== Klient i serwer ==== 
- 
-**W tym ćwiczeniu proszę zmienić numer portu na dowolny z zakresu 33700-33999,​ aby nie przeszkadzać kolegom.** 
- 
-<code prolog> 
-:- use_module(library(socket)). 
- 
-create_client :- 
- tcp_socket(Socket),​ 
- tcp_connect(Socket,​localhost:​33888),​ 
- tcp_open_socket(Socket,​Read,​Write),​ 
- write(Write,'​matka(kasia,​robert).'​),​nl(Write),​ 
- close(Read),​ 
- close(Write). 
- 
-create_server :- 
- tcp_socket(Socket),​ 
- tcp_bind(Socket,​33888),​ 
- tcp_listen(Socket,​5),​ 
- tcp_open_socket(Socket,​_,​_),​ 
- 
- tcp_accept(Socket,​ Slave, _), % Akceptacja połaczenia ze strony klienta. 
- tcp_open_socket(Slave,​ In, Out), 
- read(In,​Msg),​ % Odczyt wiadomości. 
- write(Msg),​ 
-       ​close(In),​ 
-       ​close(Out). 
-</​code>​ 
- 
-  * Predykat //​create_client/​0//​ tworzy obsługę gniazda TCP po stronie serwera, wysyła do serwera komunikat w postaci termu, a następnie zamyka połączenie. 
-  * Predykat //​create_server/​0//​ dzieli się na dwie części. Pierwsza tworzy gniazdo, a druga obsługuję przychodzące połączenie. Predykat //​tcp_accept/​3//​ oczekuje do momentu nawiązania połączenia przez klienta. 
- 
-**Ćwiczenie:​** 
- 
-Proszę wczytać powyższy program, uruchomić serwer w osobnym wątku (//​thread_create/​3//​) i nawiązać z nim połączenie. 
- 
-Następnie proszę tak zmodyfikować predykat //​create_server/​0//,​ aby był w stanie obsłużyć więcej niż jedno połączenie (niekoniecznie symultanicznie,​ może być jedno po drugim) i przy każdym dopisywał przesłany term do bazy wiedzy (//​assert/​1//​). 
- 
-==== Komunikator ==== 
- 
-Program {{komunikator.pl|komunikator}} wykorzystuje gniazda TCP w celu stworzenia w Prologu prymitywnej wymiany wiadomości między użytkownikami. Proszę się z nim zapoznać Jest podzielony na część klienta i serwera. W rzeczywistości jest to rozbudowana wersja prostego programu z przykładu zamieszczonego wyżej. Dodana jest odpowiednia interpretacja komunikatów. Owe komunikaty są przesyłane w postaci termów, więc każdy musi być zakończony kropką. 
- 
-**Ćwiczenie:​** 
- 
-Po zapoznaniu z programem proszę się porozumieć z kolegami wykonującymi to samo ćwiczenie. Niech jeden ze studentów uruchomi serwer komunikatora na ustalonym porcie przy użyciu predykatu //​start_server/​0//​. Pozostali niech się z nim połączą przy użyciu predykatu //​start_client/​1//​. Np. //​start_client(ania)//​. Proszę przetestować działanie komunikatora. 
- 
-Przykładowa sesja po stronie klienta może wyglądać następująco:​ 
-<code prolog> 
-1 ?- start_client(ania). 
-|: Server message: Hello! I am a communication server 
-Server message: Type commands: 
-|: who. 
-|: Users connected to the server: 
-     - ania 
-     - bartek 
-|: msg(bartek,"​Cześć Bartek!"​). 
-|: Message from bartek: Cześć Aniu! 
-|: quit. 
-|: Connection closed by server. 
-</​code>​ 
- 
-===== -. HTTP ===== 
- 
-W SWI-Prolog do dyspozycji są dwie biblioteki integrujące z protokołem HTTP od strony klienta: 
-  * [[http://​www.swi-prolog.org/​pldoc/​doc_for?​object=section(3%2c%20%272.1%27%2c%20swi(%27%2fdoc%2fpackages%2fhttp.html%27))|http/​http_open]] - oparta jedynie na metodzie HTTP GET, 
-  * [[http://​www.swi-prolog.org/​pldoc/​doc_for?​object=section(3%2c%20%272.2%27%2c%20swi(%27%2fdoc%2fpackages%2fhttp.html%27))|http/​http_client]] - bardziej rozbudowana. 
- 
-==== http_open - get ==== 
- 
-Biblioteka http_open jest prostsza, daje mniejsze możliwości,​ ale wystarczająca,​ jeśli ograniczamy się do ściągnięcia kodu html strony. 
- 
-Predykat //​http_open(+URL,​-Stream,​+Options)//​ otwiera strumień dla wskazanego adresu URL. Po skorzystaniu ze strumienia należy go zamknąć tak jak każdy inny strumień w prologu: //​close(+Stream)//​. 
- 
-**Ćwiczenie:​** 
- 
-<code prolog> 
-:- use_module(library(http/​http_open)). 
- 
-view_site :- 
- http_open('​http://​www.google.pl',​In,​[]),​ 
- copy_stream_data(In,​user_output),​ 
- close(In). 
-</​code>​ 
- 
-==== http_open - head ==== 
- 
-Opcja //​method(head)//​ predykatu //open/3// powoduje, że odczytywany jest tylko nagłówek strony. W połączeniu z opcją //​header(+Name,​-AtomValue)//​ można uzyskać konkretne pole nagłówka. 
- 
-**Ćwiczenie** 
- 
-<code prolog> 
-:- use_module(library(http/​http_open)). 
- 
-view_date :- 
- http_open('​http://​www.google.pl',​In,​[method(head),​header(date,​Date)]),​ 
- copy_stream_data(In,​user_output),​ 
- close(In), 
- writeln(Date). 
-</​code>​ 
- 
-Proszę odczytać także inne pola nagłowka, np. content_type (myślnik jest zastępowany przez podkreślenie). 
- 
-==== http_client - GET ==== 
- 
-Predykat //​http_get(+URL,​ -Reply, +Options)// unifikuje zmienna logiczną Reply z odpowiedzią serwera, uzyskaną przy użyciu metody GET. 
- 
-**Ćwiczenie:​** 
- 
-<code prolog> 
-:- use_module(library(http/​http_client)). 
- 
-view_site :- 
- http_get('​http://​www.google.pl',​Reply,​[]),​ 
- write(Reply). 
-</​code>​ 
- 
-==== Dla zainteresowanych ==== 
- 
-SWI-Prolog udostępnia także bibliotekę HTTP od strony serwera. Pełna dokumantacja znajduje się na stronie: [[http://​www.swi-prolog.org/​pldoc/​package/​http.html|SWI-Prolog HTTP support]]. 
- 
-====== Uwagi, komentarze, propozycje ====== 
-Tu studenci mogą wpisywać swoje uwagi. 
- 
- --- //​[[gjn@agh.edu.pl|Grzegorz J. Nalepa]] 2009/05/06 09:13// 
  
pl/prolog/prolog_lab/prolog_lab_http.txt · ostatnio zmienione: 2019/06/27 15:50 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0