Narzędzia użytkownika

Narzędzia witryny


sk2:sockets_concurrency

Różnice

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

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
Nowa wersja
Poprzednia wersja
sk2:sockets_concurrency [2023/11/09 12:30]
jkonczak [Funkcje biblioteczne]
sk2:sockets_concurrency [2024/11/12 11:52] (aktualna)
jkonczak
Linia 6: Linia 6:
 Do obsługi wielu źródeł zdarzeń stworzono dedykowane metody, można też używać typowych metod pisania aplikacji współbieżnych. Zwolennicy SE nazwą to "​wzorcami projektowymi"​. Przegląd typowych metod tworzenia aplikacji sieciowych: Do obsługi wielu źródeł zdarzeń stworzono dedykowane metody, można też używać typowych metod pisania aplikacji współbieżnych. Zwolennicy SE nazwą to "​wzorcami projektowymi"​. Przegląd typowych metod tworzenia aplikacji sieciowych:
   * Iteracyjnie – kiedy współbieżność jest zbędna.   * Iteracyjnie – kiedy współbieżność jest zbędna.
-  * Pętla zdarzeń (event loop, [[https://​en.wikipedia.org/​wiki/​Event_loop|[1]]],​ [[https://​web.archive.org/​web/​20190730174916/​https://​pl.wikipedia.org/​wiki/​Programowanie_sterowane_zdarzeniami|[2]]]) – programista wpierw przygotowuje kod (funkcje) obsługi możliwych zdarzeń, następnie w pętli czeka na zdarzenie i wywołuje kod powiązany ze zdarzeniem. Aplikacja może być jedno- lub wielowątkowa,​ muszą być dostępne funkcje czekające na zdarzenie – dla I/O pod Linuksem to ''​select'',​ ''​poll''​ i ''​epoll''​. Praktycznie wszystkie programy z GUI wykorzystują pętlę zdarzeń przynajmniej do obsługi GUI.+  * Pętla zdarzeń (event loop, [[https://​en.wikipedia.org/​wiki/​Event_loop|[1]]],​ [[https://​web.archive.org/​web/​20190730174916/​https://​pl.wikipedia.org/​wiki/​Programowanie_sterowane_zdarzeniami|[2]]]) – programista wpierw przygotowuje kod (funkcje) obsługi możliwych zdarzeń, następnie w pętli czeka na zdarzenie i wywołuje kod powiązany ze zdarzeniem. Aplikacja może być jedno- lub wielowątkowa,​ muszą być dostępne funkcje czekające na zdarzenie – dla I/O pod Linuksem to ''​select'',​ ''​poll''​ i ''​epoll''​. ​\\ Praktycznie wszystkie programy z GUI wykorzystują pętlę zdarzeń przynajmniej do obsługi GUI.
   * Aplikacja wielowątkowa – każde źródło zdarzeń – np. gniazdo – jest obsługiwane w osobnym wątku.   * Aplikacja wielowątkowa – każde źródło zdarzeń – np. gniazdo – jest obsługiwane w osobnym wątku.
 +
 ====== Wiele wątków ====== ====== Wiele wątków ======
  
 [[sk2:​cpp11_threads|Wątki w C++]] [[sk2:​cpp11_threads|Wątki w C++]]
  
-//Zadanie ​1.// Napisz własną wersję programu ''​netcat''​ wspierającą tylko klienta TCP – program, który nawiąże połączenie TCP pod wskazany adres, następnie dane przychodzące na standardowe wejście będzie wysyłać przez to połączenie,​ a dane które przyszły ​z sieci wypisze ​na standardowe wyjście.\\ (Możesz skorzystać z {{:​sk2:​tcp_client_template.cpp|przykładowego kodu}})+~~Zadanie.#~~ Napisz własną wersję programu ''​netcat''​ wspierającą tylko klienta 
 +TCP – program, który nawiąże połączenie TCP pod wskazany adres, następnie dane 
 +przychodzące na standardowe wejście będzie wysyłać przez to połączenie,​ a 
 +równocześnie ​dane przychodzące ​z sieci będzie wypisywać ​na standardowe wyjście. 
 +\\ 
 +(Możesz skorzystać z {{:​sk2:​tcp_client_template.cpp|przykładowego kodu klienta}})
  
-//Zadanie ​2.// Czat – napisz serwer, który każdą otrzymaną wiadomość przekaże wszystkim połączonym klientom. \\ +~~Zadanie.#~~ Czat – napisz serwer, który każdą otrzymaną wiadomość przekaże 
-(Możesz skorzystać z {{:​sk2:​tcp_server_template.cpp|przykładowego kodu}})+wszystkim połączonym klientom. 
 +\\ 
 +(Możesz skorzystać z {{:​sk2:​tcp_server_template.cpp|przykładowego kodu serwera}})
 ====== Zdarzenia ====== ====== Zdarzenia ======
  
Linia 22: Linia 30:
 System Linux zawiera 3 podstawowe funkcje pozwalające na czekanie na przychodzące zdarzenia na deskryptorach plików: System Linux zawiera 3 podstawowe funkcje pozwalające na czekanie na przychodzące zdarzenia na deskryptorach plików:
   * ''​select''​ – "​klasyczna"​ funkcja, ma kilka dziwnych ograniczeń. Dostaje zbiór deskryptorów,​ oczekuje na zdarzenie, modyfikuje przekazany zbiór deskryptorów zostawiając tylko te na których można wykonać read/​write/​lub na których wystąpił wyjątek. (POSIX)   * ''​select''​ – "​klasyczna"​ funkcja, ma kilka dziwnych ograniczeń. Dostaje zbiór deskryptorów,​ oczekuje na zdarzenie, modyfikuje przekazany zbiór deskryptorów zostawiając tylko te na których można wykonać read/​write/​lub na których wystąpił wyjątek. (POSIX)
-  * ''​poll''​ – zbudowana podobnie jak ''​select'',​ ale m.inn. nie ma ograniczenia na numery monitorowanych deskryptorów((Patrz [[https://​man7.org/​linux/​man-pages/​man2/​select.2.html|man 2 select]].)),​ można użyć ponownie struktury opisującej deskryptory etc. (POSIX) +  * ''​poll''​ – zbudowana podobnie jak ''​select'',​ ale m. inn. nie ma ograniczenia na numery monitorowanych deskryptorów((Patrz [[https://​man7.org/​linux/​man-pages/​man2/​select.2.html|man 2 select]].)),​ można użyć ponownie struktury opisującej deskryptory etc. (POSIX) 
-  * ''​epoll''​ – specyficzna dla Linuksa funkcja. Inny pomysł: program informuje jądro systemu na które deskryptory chce czekać, potem wywołuje funkcję czekającą na zdarzenie i dostaje ​deskryptory ​które ​są gotowe do pracy.+  * ''​epoll''​ – specyficzna dla Linuksa funkcja. Inny pomysł: program informuje jądro systemu na które deskryptory chce czekać, potem wywołuje funkcję czekającą na zdarzenie i dostaje ​informacje ​które ​zarzenia wystąpiły.
  
 Dłuższe porównanie:​ http://​www.ulduzsoft.com/​2014/​01/​select-poll-epoll-practical-difference-for-system-architects/​ Dłuższe porównanie:​ http://​www.ulduzsoft.com/​2014/​01/​select-poll-epoll-practical-difference-for-system-architects/​
Linia 30: Linia 38:
 ===== poll ===== ===== poll =====
  
-Aby stworzyć program korzystający z funkcji ''​poll'',​ należy: +Aby stworzyć program korzystający z funkcji ''​poll'',​ należy:<​html><​div style="​margin-top:-1.4em"></​div></​html>​
-  ​dodać plik nagłówkowy ''​poll.h''​+
   - przygotować tablicę struktur ''​pollfd''​ i wypełnić:   - przygotować tablicę struktur ''​pollfd''​ i wypełnić:
     * ''​.fd''​ – deskryptor pliku do monitorowania,​     * ''​.fd''​ – deskryptor pliku do monitorowania,​
     * ''​.events''​ – zbiór monitorowanych zdarzeń:     * ''​.events''​ – zbiór monitorowanych zdarzeń:
       *  ''​POLLIN''​ – funkcja ''​poll''​ ma się przerwać, jeśli można wywołać bez czekania ''​read()/​…''​ lub ''​acccept()''​       *  ''​POLLIN''​ – funkcja ''​poll''​ ma się przerwać, jeśli można wywołać bez czekania ''​read()/​…''​ lub ''​acccept()''​
-      *  ''​POLLOUT''​ – funkcja ''​poll''​ ma się przerwać, jeśli można wywołać bez czekania ''​write()/​…''​ \\ Uwaga: na możliwość wysłania danych czeka się wtedy kiedy ma się dane do wysłania \\ Uwagajeśli spróbujesz zapisać ​więcej bajtów niż jest miejsca w buforze nadawczym''​write'' ​i tak się zablokuje<​html></​div></​li></​ul><​div class="​li"></​html>​ reszta zdarzeń (''​POLLHUP'',​ ''​POLLERR'',​ ''​POLLPRI'',​ …) opisana w ''​man poll''​ <​html></​div><​!--</​html>​+      *  ''​POLLOUT''​ – funkcja ''​poll''​ ma się przerwać, jeśli można wywołać bez czekania ''​write()/​…''​ \\ //uwaga//: na możliwość wysłania danych czeka się wtedy kiedy ma się dane do wysłania \\ //uwaga//próba zapisania ​większej liczby ​bajtów niż jest wolnego ​miejsca w buforze nadawczym ​i tak zablokuje ​''​write''<​html></​div></​li></​ul><​div class="​li"></​html>​//uwaga//: jeśli na gnieździe wystąpił błąd, to ''​read()/​write()/​…''​ też można wywołać bez czekania \\ reszta zdarzeń (''​POLLHUP'',​ ''​POLLERR'',​ ''​POLLPRI'',​ …) opisana w ''​man poll''​ <​html></​div><​!--</​html>​
     * <​html>​--><​div class="​li"></​html>​     * <​html>​--><​div class="​li"></​html>​
     * zostawić w spokoju ''​.revents''​ – tam pojawi się informacja o tym co wystąpiło     * zostawić w spokoju ''​.revents''​ – tam pojawi się informacja o tym co wystąpiło
-  - w pętli wywoływać funkcję ''​poll(…)''​. ​Uwaga: ​aby funkcja czekała ​w nieskończoność''​timeout''​ musi być ujemny+  - w pętli wywoływać funkcję ''​poll(…)''​. ​\\ <​small>​ostatni argument funkcji ''​poll''​ to maksymalny czas oczekiwania; ​aby funkcja czekała ​bez limitunależy podać tam dowolną ujemną wartość</​small>​
   - sprawdzać który deskryptor jest gotowy przeglądając pola ''​.revents''​   - sprawdzać który deskryptor jest gotowy przeglądając pola ''​.revents''​
  
-<code cpp> +Funkcja ''​poll'',​ struktura ''​pollfd''​ i stałe ''​POLL…'' ​ są w pliku nagłówkowym ''#​include ​<poll.h>''​
-pollfd σληζονε[ιλε]; ​                      ​─┐ +
-σληζονε[0].fd = σοκητ_α; ​                   │ +
-σληζονε[0].events = POLLIN; ​                ​├─ (2) +
-σληζονε[1].fd = σοκητ_β; ​                   │ +
-σληζονε[1].events = POLLIN; ​               ─┘ +
-...+
  
-while(true{ +<​html>​ 
-    int γωτουε ​= poll(σληζονειλε, -1);   ═╾─ ​(3)+<pre class="​code cpp" style="​user-select:​ none; line-height:​ 100%">​ 
 +<span title="​Tablica struktur '​pollfd'​ opisująca na których plikach i na co czekać"​ style="​background-color:#​fb02">​pollfd pfds<​span class="​br0">​[</​span>​COUNT<​span class="​br0">​]</​span><​span class="​br0">​{</​span><​span class="​br0">​}</​span><​span class="​sy4">;</​span></​span> ​                                         <span style="​color:​grey">​─┐</​span>​ 
 +<span title="​poll() może monitorować dowolne pliki, np. standardowe wejście"​ style="​background-color:#​f002">​pfds<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span>​.<​span class="​me1">​fd</​span>​ <span class="​sy1">​=</​span>​ STDIN_FILENO<​span class="​sy4">;</​span></​span> ​  ​pfds<​span class="​br0">​[</​span><​span class="​nu0">​2</​span><​span class="​br0">​]</​span><​span title="'​fd'​ wskazuje na którm pliku czekać na zdarzena, a '​events'​ określa na które zdarzenia na wskazanym pliku" style="​background-color:#​0f02">​.<​span class="​me1">​fd</​span>​ <span class="​sy1">​=</​span></​span>​ cliSock1<​span class="​sy4">;</​span> ​            <​span style="​color:​grey">​│</​span>​ 
 +<span title="poll() może monitorować dowolne plikinp. standardowe wejście"​ style="​background-color:#​f002">​pfds<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span>​.<​span class="​me1">​events</​span>​ <span class="​sy1">​=</​span>​ POLLIN<​span class="​sy4">;</​span></​span> ​    ​pfds<​span class="​br0">​[</​span><​span class="​nu0">​2</​span><​span class="​br0">​]</​span><​span title="'​fd'​ wskazuje na którm pliku czekać na zdarzenaa '​events'​ określa na które zdarzenia na wskazanym pliku" style="​background-color:#​0f02">​.<​span class="​me1">​events</​span>​ <span class="​sy1">​=</​span></​span>​ POLLIN<​span class="​sy4">;</​span> ​          <​span style="​color:​grey">​├─ (1)</​span>​ 
 +<span title="​Na gnieździe nasłuchującym POLLIN oznacza możliwość wykonania accept() bez czekania"​ style="​background-color:#​00f2">​pfds<​span class="​br0">​[</​span><​span class="​nu0">​1</​span><​span class="​br0">​]</​span>​.<​span class="​me1">​fd</​span>​ <span class="​sy1">​=</​span>​ serverSock<​span class="​sy4">​;</​span></​span> ​    ​pfds<​span class="​br0">​[</​span><​span class="​nu0">​3</​span><​span class="​br0">​]</​span>​.<​span class="​me1">​fd</​span>​ <span class="​sy1">​=</​span>​ cliSock2<​span class="​sy4">;</​span> ​            <​span style="​color:​grey">​│</​span>​ 
 +<span title="​Na gnieździe nasłuchującym POLLIN oznacza możliwość wykonania accept() bez czekania"​ style="​background-color:#​00f2">​pfds<​span class="​br0">​[</​span><​span class="​nu0">​1</​span><​span class="​br0">​]</​span>​.<​span class="​me1">​events</​span>​ <span class="​sy1">​=</​span>​ POLLIN<​span class="​sy4">;</​span></​span> ​    ​pfds<​span class="​br0">​[</​span><​span class="​nu0">​3</​span><​span class="​br0">​]</​span>​.<​span class="​me1">​events</​span>​ <span class="​sy1">​=</​span>​ <span title="​Jeśli zostanie podane POLLIN, to 'poll()' zakończy się kiedy tylko będzie dało się bez czekania wykonać '​read'​ (w buforze są dane lub wystąpił błąd na gnieździe)"​ style="​background-color:#​0ff4">​POLLIN</​span><​span class="​sy3">​|</​span><​span title="​Jeśli zostanie podane POLLOUT, to '​poll()'​ zakończy się kiedy tylko będzie dało się bez czekania wykonać '​write'​ (tzn. da się wysłać przynajmniej jeden bajt lub wystąpił błąd na gnieździe)"​ style="​background-color:#​ff04">​POLLOUT</​span><​span class="​sy4">;</​span> ​ <span style="​color:​grey">​─┘</​span>​ 
 +...                          ...
  
-    ​if(σληζονε[0].revents & POLLIN){       ─┐ ​  +<span class="​kw1">​while</​span><​span class="​br0">​(</​span><​span class="​nu0">​1</​span><​span class="​br0">​)</​span><​span class="​br0">​{</​span>​ 
-        read(σοκητ_α, ​...                   │ +    <span class="​kw4">​int</​span>​ ile_gotowych <span class="​sy1">​=</​span>​ poll<​span class="​br0">​(</​span><​span title="​Tablica struktur '​pollfd'​ opisująca na których plikach i na co czekać"​ style="​background-color:#​fb02">​pfds</​span>,​ <span title="​Wskazuje ile struktur pod wskaźnikiem '​pfds'​ ma odczytać funkcja '​poll'"​ style="​background-color:#​f082">​liczbaStruktur</​span>,​ <span title="​Limit czasu oczekiwania na pierwsze zdarzenie:​ 
-        ...                                 │ +nieujemna wartość: maksymalny czas czekania w milisekundach,​ 
-    ​}                                       ​├─ ​(4+ujemna wartość: czekanie bez limitu czasowego"​ style="​background-color:#​0002"><​span class="​sy2">​-</​span><​span class="​nu0">​1</​span></​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span> ​        <​span style="​color:​grey">​═╾─ (2)</​span>​ 
-    if(σληζονε[1].revents & POLLIN){        │ + 
-        read(σοκητ_β, ​...                   │ +    <span title="​poll() może monitorować dowolne pliki, np. standardowe wejście"​ style="​background-color:#​f002"><​span class="​kw1">​if</​span><​span class="​br0">​(</​span>​pfds<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span>​.<span class="​me1">​revents</​span>​ <span class="​sy3">​&amp;</​span> ​POLLIN<span class="​br0">​)</​span>​ readingFromStdin<​span class="​br0">​(</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span></​span> ​          <​span style="​color:​grey">​─┐</​span>​ 
-        ...                                ─┘ +    <​span class="​kw1">​if</​span><​span class="​br0">​(</​span>​pfds<​span class="​br0">​[</​span><​span class="​nu0">​1</​span><​span class="​br0">​]</​span><​span title="​poll() wypełnia pole .revents, wpisując tam identyfikatory wszystkich zdarzeń które wystąpiły na pliku" style="​background-color:#​0f42">​.<span class="​me1">​revents</​span>​ <span class="​sy3">&​amp;</​span></​span>​ POLLIN<​span class="​br0">​)</​span>​ acceptingNewClient<​span class="​br0">​(</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span> ​         <span style="​color:​grey">​</​span>​ 
-    } +    ​<span class="​kw1">​for</​span><​span class="​br0">​(</​span><​span class="​kw4">​int</​span>​ i <span class="​sy1">​=</​span>​ <span class="​nu0">​2</​span><​span class="​sy4">;</​span>​ i <span class="​sy1">&​lt;</​span>​ liczbaStruktur<​span class="​sy4">;</​span>​ <span class="​sy2">​++</​span>​i<​span class="​br0">​)</​span><​span class="​br0">​{</​span> ​                   <span style="​color:​grey">​│</​span>​ 
-    ... +        <​span title="​Jeśli zostanie podane POLLIN, to '​poll()'​ zakończy się kiedy tylko będzie dało się bez czekania wykonać '​read'​ (w buforze są dane lub wystąpił błąd na gnieździe)"​ style="​background-color:#​0ff4"><​span class="​kw1">​if</​span><​span class="​br0">​(</​span>​pfds<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<span class="​me1">​revents</​span>​ <span class="​sy3">​&amp;</​span> ​POLLIN<span class="​br0">​)</​span></​span> ​                           <span style="​color:​grey">​├─ (3)</​span>​ 
-+            <​span title="​Jeśli zostanie podane POLLIN, to '​poll()'​ zakończy się kiedy tylko będzie dało się bez czekania wykonać 'read' ​(w buforze są dane lub wystąpił błąd na gnieździe)"​ style="​background-color:#​0ff4">​readFromClient<​span class="​br0">​(</​span>​pfds<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<span class="​me1">​fd</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span></​span> ​                        <​span style="​color:​grey">​</​span>​ 
-</code>+        ​<span title="​Jeśli zostanie podane POLLOUT, to '​poll()'​ zakończy się kiedy tylko będzie dało się bez czekania wykonać '​write'​ (tznda się wysłać przynajmniej jeden bajt lub wystąpił błąd na gnieździe)"​ style="​background-color:#​ff04"><​span class="​kw1">​if</​span><​span class="​br0">​(</​span>​pfds<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<span class="​me1">​revents</​span>​ <span class="​sy3">&​amp;</​span>​ POLLOUT<​span class="​br0">​)</​span></​span> ​                          <​span style="​color:​grey">​│</​span>​ 
 +            <span title="​Jeśli zostanie podane POLLOUT, to '​poll()'​ zakończy się kiedy tylko będzie dało się bez czekania wykonać '​write'​ (tznda się wysłać przynajmniej jeden bajt lub wystąpił błąd na gnieździe)"​ style="​background-color:#​ff04">​writeToClient<​span class="​br0">​(</​span>​pfds<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<​span class="​me1">​fd</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span></​span> ​                        <​span style="​color:​grey">​─┘</​span>​ 
 +    ​<span class="​br0">​}</​span>​ 
 +<span class="​br0">​}</​span>​ 
 +</pre> 
 +</​html>​ 
 + 
 +~~Zadanie.#​~~ Powtórz Zadanie 1, ale tym razem jako jednowątkowy program wykorzystujący ''​poll''​. 
 +\\ 
 +(Możesz skorzystać z {{:​sk2:​tcp_client_template.cpp|przykładowego kodu klienta}})
  
-//Zadanie 3.// Powtórz Zadanie 1, ale tym razem jako jednowątkowy program wykorzystujący ''​poll''​. 
 ===== epoll ===== ===== epoll =====
  
Linia 73: Linia 88:
   - Funkcja czekająca na zdarzenia – ''​epoll_wait''​ – przyjmuje jako argumenty tylko deskryptor utworzony przez ''​epoll_create'',​ tablicę zdarzeń do wypełnienia i czas oczekiwania (-1 = nieskończoność). \\   - Funkcja czekająca na zdarzenia – ''​epoll_wait''​ – przyjmuje jako argumenty tylko deskryptor utworzony przez ''​epoll_create'',​ tablicę zdarzeń do wypełnienia i czas oczekiwania (-1 = nieskończoność). \\
   - ''​epoll_wait''​ nie przekazuje numerów gotowych deskryptorów – przekazuje tylko rodzaj zdarzenia i powiązane z nim wcześniej dane.   - ''​epoll_wait''​ nie przekazuje numerów gotowych deskryptorów – przekazuje tylko rodzaj zdarzenia i powiązane z nim wcześniej dane.
-Plik nagłówkowy: ​''#​include <​sys/​epoll.h>''​+Funkcje ''​epoll_…'',​ struktura ''​epoll_event''​ i stałe ''​EPOLL…''​ są w pliku nagłówkowym ​''#​include <​sys/​epoll.h>''​
  
-<code cpp> +<html> 
-int εΦδ ​= epoll_create1(0); ​                      ​═╾─ (1)         +<pre class="​code cpp" style="​user-select:​ none; line-height:​ 100%"
-                                                               ​ +<span title="​Pomocnicze zmienne, struktury i funkcje"​ style="​opacity:​ 0.75; background-color:#​0001"><​span class="​kw4">​struct</​span>​ Client <span class="​br0">​{</​span>​ 
-epoll_event ​ωπις                                ​─┐ ​              +    <span class="​kw4">​int</​span>​ fd<span class="​sy4">;</​span>​ 
-ωπις.events = EPOLLIN; ​                            ​│               +    <span class="​kw4">​char</​span>​ <span class="​sy2">​*</​span>​partialDataReceived,​ <span class="​sy2">​*</​span>​dataQueuedToSend<​span class="​sy4">;</​span>​ 
-ωπις.data.u64 = 987654321                        │              +<span class="​br0">​}</​span>​ <span class="​sy2">​*</​span>​clients<​span class="​sy4">;</​span>​ 
-epoll_ctl(εΦδ, EPOLL_CTL_ADD, ​σοκητ_α, &ωπις)    ├─ (2+<span class="​kw4">​void</​span>​ receiveFromCli<​span class="​br0">​(</​span>​Client <span class="​sy2">​*</​span>​c<​span class="​br0">​)</​span><​span class="​sy4">;</​span>​ 
-ωπις.data.u64 123456789                        ​│ +<span class="​kw4">​void</​span>​ sendQueuedData<​span class="​br0">​(</​span>​Client <span class="​sy2">​*</​span>​c<​span class="​br0">​)</​span><​span class="​sy4">;</​span></​span>​ 
-epoll_ctl(εΦδ, EPOLL_CTL_ADD, ​σοκητ_β, &ωπις);     │ + 
-...                                               ─┘ ​              +... 
-// Poza .u64 w unii są też .fd i .ptr + 
-                                                                    ​ +  <span title="'​epoll_create1' tworzy nowy plik do monitorowania zdarzeń na innych plikach"​ style="​background-color:#​ff02"><​span class="​kw4">​int</​span>​ epollDescr <span class="​sy1">​=</​span>​ epoll_create1<​span class="​br0">​(</​span><​span class="​nu0">​0</​span><​span class="​br0">​)</​span><​span class="​sy4">​;</​span></​span> ​                                  ═╾─ (1) 
-while(true) {                                                       ​ + 
-    int γωτουε ​= epoll_wait(εΦδ&​ωπις1, -1);   ​═╾─ (3)           +  <​span title="​Struktura ​epoll_event ​jest używana: 
-                                                                     +1) w epoll_ctl jako argument wejściowy, do określenia na jakie zdarzenia czekać i powiązania z nimi danych 
-    if(ωπις.events ​EPOLLIN && ​                  ─┐ ​                    +2) w epoll_wait jako argument wyjściowy, określa jakie zdarzenia wystąpiły i przekazania powiązanych z nimi danych"​ style="​background-color:#​f802">​epoll_event</​span>​ ee<span class="​br0">​[</​span><​span class="​nu0">​2</​span><​span class="​br0">​]</​span><​span class="​sy4">​;</​span> ​                                                  ─┐ 
-       ωπις.data.u64 == 987654321 ​){               ​│                   +  ​ee<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span><​span title="'​.events' określa które zdarzenia mają być raportowane"​ style="​background-color:#​0f02">​.<​span class="​me1">​events</​span>​ <span class="​sy1">​=</​span></​span> ​EPOLLIN<span class="​sy4">​;</​span> ​                                              │ 
-       read(σοκητ_α, ...                           │                   +  ​ee<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span><​span title="​Jeśli wskazane zdarzenie wystąpi, to (skopiowana do pamięci systemu operacyjngo w momencie wywołania '​epoll_ctl'​) wartość unii '.data' zostanie z powrotem wpisana przez '​epoll_wait'​ do wynikowej struktury epoll_event 
-    ​} ​                                             ​├─ (4) +W tej unii do wybor są pola fd, u32, u64 i ptr, odpowiednio typów int, uint32_t, uint64_t i void*" style="​background-color:#​f002">​.<​span class="​me1">​data</​span>​.<​span class="​me1">​u32</​span>​ <span class="​sy1">​=</​span></​span>​ <span class="​sy2">​-</​span><​span class="​nu0">​1</​span><​span class="​sy4">​;</​span> ​                                                 ├─ (2) 
-    if(ωπις.events & EPOLLIN ​&& ​                   ​│ +  <​span title="'​epoll_ctl' zarządza listą zdarzeń które monitoruje wskazany plik epoll: 
-       ωπις.data.u64 == 123456789 ​){               │ +z flagą EPOLL_CTL_ADD dodaje nowy plik, 
-       read(σοκητ_β, ​...                          ​─┘ +z flagą EPOLL_CTL_DEL przestaje monitorować wskazany plik, 
-    +z flagą EPOLL_CTL_MOD zmienia listę zdarzeń i powiązane dane dla już monitorowanego pliku" style="​background-color:#​f0f2">​epoll_ctl</​span><​span class="​br0">​(</​span>​epollDescr<span title="'​epoll_ctl'​ zarządza listą zdarzeń które monitoruje wskazany plik epoll: 
-    ... +z flagą ​EPOLL_CTL_ADD ​dodaje nowy plik, 
-+z flagą EPOLL_CTL_DEL przestaje monitorować wskazany plik, 
-</code>+z flagą EPOLL_CTL_MOD zmienia listę zdarzeń i powiązane dane dla już monitorowanego pliku" style="​background-color:#​f0f2">​EPOLL_CTL_ADD</​span>,​ STDIN_FILENO,​ <span class="​sy3">​&amp;</​span>​ee<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span> ​          │ 
 +  ​ee<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span>​.<span class="​me1">​data</​span>​.<span class="​me1">​u32</​span>​ <span class="​sy1">​=</​span>​ <span class="​sy2">​-</​span><​span class="​nu0">​2</​span><​span class="​sy4">​;</​span> ​                                                 ​│ 
 +  epoll_ctl<span class="​br0">​(</​span><​span title="​Wybiera na którym z plików epoll będzie pracować ta funkcja"​ style="​background-color:#​0fa2">​epollDescr</​span>​, EPOLL_CTL_ADD, ​<span title="​Określa na którym pliku należy rozpocząć (lub zmienić/​zakończyć) śledzenie zdarzeń"​ style="​background-color:#​0082">​serverSock</​span>​<span title="​Wskazuje które zdarzenia mają być raportowane i jakie dane programista chce otrzymać, kiedy wskazane zdarzenie wystąpi"​ style="​background-color:#​a0f2"><​span class="​sy3">​&amp;</​span>​ee<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span><​span class="​br0"></​span></​span>​)<span class="​sy4">​;</​span> ​           ​─┘  
 + 
 +  <​span class="​kw1">​while</​span>​ <span class="​br0">​(</​span><​span class="​nu0">​1</​span><​span class="​br0">​)</​span>​ <span class="​br0">​{</​span>​ 
 +      <​span title="'​epoll_wait'​ zwraca ile pierwszych struktur z podanej listy wypełnił"​ style="​background-color:#​f402"><​span class="​kw4">​int</​span>​ ile_gotowych</​span>​ <span class="​sy1">​=</​span>​ <span title="'​epoll_wait' wpisuje do podanej listy struktur epoll_event listę zdarzeń które wystąpiły na wcześniej zgłoszonych do monitorowania plikach ​(jeśli trzebaczekając na pierwsze zdarzenie)"​ style="​background-color:#​0ff2">​epoll_wait</​span><​span class="​br0">​(</​span><​span title="​Wybiera na którym z plików epoll będzie pracować ta funkcja"​ style="​background-color:#​0fa2">​epollDescr</​span>​<span title="​wskazuje że wyniki mają trafić do tablicy '​ee'​ w której jest miejsce na co najwyżej 2 elementy"​ style="​background-color:#​8f03">​ee<span class="​nu0">​2</​span></​span>,​ <span title="​limit czasu oczekiwania (jak w poll)" style="​background-color:#​0001"><​span class="​sy2">​-</​span><​span class="​nu0">​1</​span></​span><​span class="​br0">​)</​span><​span class="​sy4">​;</​span> ​           ​═╾─ (3) 
 + 
 +      <​span class="​kw1">​for</​span>​ <span class="​br0">​(</​span><​span class="​kw4">​int</​span>​ i <span class="​sy1">​=</​span>​ <span class="​nu0">​0</​span><​span class="​sy4">;</​span>​ i <span class="​sy1">​&lt;</​span>​ ile_gotowych<​span class="​sy4">;</​span>​ <span class="​sy2">​++</​span>​i<​span class="​br0">​)</​span>​ <span class="​br0">​{</​span> ​                        ─┐ 
 +          <​span class="​kw1">​if</​span>​ <span class="​br0">​(</​span>​ee<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<span class="​me1">​data</​span>​.<span class="​me1">​u32</​span>​ <span class="​sy1">​==</​span>​ <span class="​sy2">​-</​span><​span class="​nu0">​1</​span><​span class="​br0">​)</​span> ​                                    │ 
 +              readingFromStdin<​span class="​br0">​(</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span> ​                                      │ 
 +          <span class="​kw1">​else</​span>​ <span class="​kw1">​if</​span>​ <span class="​br0">​(</​span>​ee<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<​span class="​me1">​data</​span>​.<​span class="​me1">​u32</​span>​ <span class="​sy1">​==</​span>​ <span class="​sy2">​-</​span><​span class="​nu0">​2</​span><​span class="​br0">​)</​span>​ <span class="​br0">​{</​span> ​                             ​│ 
 +              <​span class="​kw4">​int</​span>​ cliFd <span class="​sy1">​=</​span>​ accept<​span class="​br0">​(</​span>​serverSock<span class="​nu0">​0</​span>,​ <span class="​nu0">​0</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span> ​                    │ 
 +              <span class="​kw4">​int</​span>​ cliId <span class="​sy1">​=</​span>​ getFreeClientId<​span class="​br0">​(</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span> ​                           │ 
 +              clients<​span class="​br0">​[</​span>​cliId<​span class="​br0">​]</​span>​ <span class="​sy1">​=</​span>​ <span class="​br0">​{</​span>​.<span class="​me1">​fd</​span>​ <span class="​sy1">​=</​span>​ cliFd<​span class="​br0">​}</​span><​span class="​sy4">;</​span> ​                          │ 
 +              ​ee<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span>​.<​span class="​me1">​events</​span>​ <span class="​sy1">​=</​span>​ EPOLLIN<​span class="​sy4">;</​span> ​                              ​┐ ​  │ 
 +              ee<span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span>​.<​span class="​me1">​data</​span>​.<​span class="​me1">​u32</​span>​ <span class="​sy1">​=</​span>​ cliId<​span class="​sy4">;</​span> ​                              ​├(2)├─ (4) 
 +              ​epoll_ctl<​span class="​br0">​(</​span>​epollDescr,​ EPOLL_CTL_ADD,​ cliFd, <span class="​sy3">&​amp;</​span>​ee<​span class="​br0">​[</​span><​span class="​nu0">​0</​span><​span class="​br0">​]</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span> ​ ┘   │ 
 +          <span class="​br0">​}</​span>​ <span title="​W tym przykładzie programista używa wartości specjalne -2 i -1 dla standardowego wejścia i gniazda serwerowego,​ a pozostałe wartości pola .data.u32 to indeksy w tablicy klientów, co ułatwia odnalezienie danych powiązanych z klientem"​ style="​background-color:#​0ff4"><​span class="​kw1">​else</​span></​span>​ <span class="​br0">​{</​span> ​                                                     │ 
 +              <span class="​kw1">​if</​span>​ <span class="​br0">​(</​span>​ee<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<span class="​me1">​events</​span>​ <span class="​sy3">​&amp;</​span> ​EPOLLIN<span class="​br0">​)</​span> ​                              │ 
 +                  ​receiveFromCli<​span class="​br0">​(</​span><​span class="​sy3">&​amp;</​span>​clients<​span class="​br0">​[</​span>​ee<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<span class="​me1">​data</​span>​.<span class="​me1">​u32</​span><​span class="​br0">​]</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span> ​            │ 
 +              <​span class="​kw1">​if</​span>​ <span class="​br0">​(</​span>​ee<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<span class="​me1">​events</​span>​ <span class="​sy3">&​amp;</​span>​ EPOLLOUT<​span class="​br0">​)</​span> ​                             │ 
 +                  sendQueuedData<​span class="​br0">​(</​span><​span class="​sy3">&​amp;</​span>​clients<​span class="​br0">​[</​span>​ee<​span class="​br0">​[</​span>​i<​span class="​br0">​]</​span>​.<span class="​me1">​data</​span>​.<span class="​me1">​u32</​span><​span class="​br0">​]</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span> ​            │ 
 +          <​span class="​br0">​}</​span> ​                                                            │ 
 +      <​span class="​br0">​}</​span> ​                                                               ─┘ 
 +  <​span class="​br0">​}</​span>​ 
 +</pre> 
 +</html>
  
 ++++Przykład użycia pola ''​.data.ptr''​| ++++Przykład użycia pola ''​.data.ptr''​|
-<code cpp> +<html> 
-struct Handler { +<pre class="​code cpp" style="​user-select:​ none; line-height:​ 100%"
-    virtual void handleEvent(uint32_t event) = 0; +<span style="​background-color:#​0001"​ title="​Każdy wskaźnik umieszczany w danych powiązanych ze zdarzeniem w epoll będzie obiektem z klasy która dziedziczy po Handler, więc będzie mieć metodę '​handle'"><​span class="​kw4">​struct</​span> ​Handler ​<span class="​br0">​{</​span>​ 
-};+    ​<span class="​kw2">​virtual</​span>​ <span class="​kw4">​void</​span>​ handle<​span class="​br0">​(</​span>​epoll_event <span class="​sy3">&​amp;</​span>​ee<​span class="​br0">​)</​span>​ <span class="​sy1">​=</​span>​ <span class="​nu0">​0</​span><​span class="​sy4">​;</​span>​ 
 +    <​span style="​opacity:​0.66"><​span class="​kw2">​virtual</​span>​ ~Handler<​span class="​br0">​(</​span><​span class="​br0">​)</​span>​ <span class="​br0">​{</​span><​span class="​br0">​}</​span></​span>​ 
 +<span class="​br0">​}</​span><​span class="​sy4">​;</​span></​span>​
  
-struct Client : public Handler { +<span style="​opacity:​0.66"><​span class="​kw4">​struct</​span>​ Client<​span class="​sy4">;</​span>​ 
-    ​Client(int fd)+std<span class="​sy4">::</​span><​span class="​me2">​set</​span><​span class="​sy1">&​lt;</​span>​Client <span class="​sy2">​*</​span><​span class="​sy1">&​gt;</​span>​ clients<​span class="​sy4">;</​span></​span>​ 
-    int fd; +<span style="​background-color:#​8001"​ title="​Klasa Client ma obsługiwać jednego klienta – czytać z jego gniazda i pisać do niego (w tym przechowywać koleję danych do wysłania i początki częściowo dostarczoncyh wiadomości),​ może też od razu zawierać logikę obsługi klienta"><​span class="​kw4">​struct</​span> ​Client</​span>​ <span class="​sy4">​:</​span>​ <span class="​kw2">​public</​span> ​Handler ​<span class="​br0">​{</​span>​ 
-    ​virtual void handleEvent(uint32_t eventoverride ​+    ​<span style="​opacity:​0.66"><​span class="​kw4">​char</​span>​ <span class="​sy2">​*</​span>​partialDataReceived,​ <span class="​sy2">​*</​span>​dataQueuedToSend<​span class="​sy4">​;</​span>​ 
-        ​if(event & EPOLLIN)+    ​<span class="​kw4">​int</​span>​ epollDescr, ​fd<span class="​sy4">​;</​span></​span>​ 
-            read(fd, ... +<span style="​background-color:#​0081"​ title="​W konstruktorze klasa Client automatycznie dodaje obsługiwane przez siebie gniazdo do monitorowania"> ​   Client<​span class="​br0">​(</​span><​span class="​kw4">​int</​span>​ epollDescr, <span class="​kw4">​int</​span>​ fd<span class="​br0">​)</​span>​ <span class="​sy4">:</​span>​ epollDescr<​span class="​br0">​(</​span>​epollDescr<​span class="​br0">​)</​span>,​ fd<span class="​br0">​(</​span>​fd<​span class="​br0">​)</​span>​ <span class="​br0">​{</​span>​ 
-        }+        ​epoll_event ee<span class="​br0">​{</​span>​.<​span class="​me1">​events</​span>​ <span class="​sy1">​=</​span> ​EPOLLIN, .<span class="​me1">​data</​span>​ <span class="​sy1">​=</​span>​ <span class="​br0">​{</​span>​.<​span class="​me1">​ptr</​span>​ <span class="​sy1">​=</​span>​ <span class="​kw3">​this</​span><​span class="​br0">​}</​span><​span class="​br0">​}</​span><​span class="​sy4">;</​span>​ 
 +        ​epoll_ctl<​span class="​br0">​(</​span>​epollDescr,​ EPOLL_CTL_ADD, ​fd, <span class="​sy3">&​amp;</​span>​ee<​span class="​br0">​)</​span><​span class="​sy4">;</​span>​ 
 +        <span style="​opacity:​0.66">​clients.<span class="​me1">​insert</​span><​span class="​br0">​(</​span><​span class="​kw3">​this</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span></​span>​ 
 +    <​span class="​br0">​}</​span></​span>​ 
 +<span style="​background-color:#​0801"​ title="​W destruktorze klasa Client zamyka gniazdo, co automatycznie usuwa gniazdo ze wszystkich epolli"> ​   ~Client<​span class="​br0">​(</​span><​span class="​br0">​)</​span>​ <span class="​br0">​{</​span>​ 
 +        close<​span class="​br0">​(</​span>​fd<​span class="​br0">​)</​span><​span class="​sy4">;</​span>​
         ...         ...
-    }+    ​<span class="​br0">​}</​span></​span>​ 
 +    <span style="​opacity:​0.66"><​span class="​kw4">​void</​span>​ receive<​span class="​br0">​(</​span>​epoll_event <span class="​sy3">&​amp;</​span>​ee<​span class="​br0">​)</​span><​span class="​sy4">;</​span>​ 
 +    <span class="​kw4">​void</​span>​ sendQueuedData<​span class="​br0">​(</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span></​span>​ 
 +    <span class="​kw4">​void</​span>​ handle<​span class="​br0">​(</​span>​epoll_event <span class="​sy3">&​amp;</​span>​ee<​span class="​br0">​)</​span>​ <span class="​br0">​{</​span>​ 
 +<span style="​background-color:#​0001"​ title="​Zwróć uwagę że poza odbieraniem danych funkcja '​receive'​ musi też obsłużyć błędy na gnieździe"> ​       <span class="​kw1">​if</​span>​ <span class="​br0">​(</​span>​ee.<​span class="​me1">​events</​span>​ <span class="​sy3">&​amp;</​span>​ EPOLLIN<​span class="​br0">​)</​span>​ 
 +            receive<​span class="​br0">​(</​span>​ee<​span class="​br0">​)</​span><​span class="​sy4">;</​span></​span>​ 
 +        <span class="​kw1">​if</​span>​ <span class="​br0">​(</​span>​ee.<​span class="​me1">​events</​span>​ <span class="​sy3">&​amp;</​span>​ EPOLLOUT<​span class="​br0">​)</​span>​ 
 +            sendQueuedData<​span class="​br0">​(</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span>​ 
 +    <span class="​br0">​}</​span>​
     ...     ...
-};+<span class="​br0">​}</​span><​span class="​sy4">​;</​span>​ 
 +<span class="​kw4">​struct</​span>​ Server <span class="​sy4">:</​span>​ <span class="​kw2">​public</​span>​ Handler <span class="​br0">​{</​span>​ 
 +    <span style="​opacity:​0.66"><​span class="​kw4">​int</​span>​ epollDescr, serverSock<​span class="​sy4">;</​span></​span>​ 
 +<span style="​background-color:#​0081"​ title="​W konstruktorze klasa Serwer tworzy nowe nasłuchujące gniazdo i dodaje je do monitorowania we wskazanym epollu"> ​   Server<​span class="​br0">​(</​span><​span class="​kw4">​int</​span>​ epollDescr, <span class="​kw4">​uint16_t</​span>​ port<​span class="​br0">​)</​span>​ <span class="​sy4">:</​span>​ epollDescr<​span class="​br0">​(</​span>​epollDescr<​span class="​br0">​)</​span>​ <span class="​br0">​{</​span>​ 
 +        serverSock <span class="​sy1">​=</​span>​ ... 
 +        ... 
 +        epoll_event ee<span class="​br0">​{</​span>​.<​span class="​me1">​events</​span>​ <span class="​sy1">​=</​span>​ EPOLLIN, .<span class="​me1">​data</​span>​ <span class="​sy1">​=</​span>​ <span class="​br0">​{</​span>​.<​span class="​me1">​ptr</​span>​ <span class="​sy1">​=</​span>​ <span class="​kw3">​this</​span><​span class="​br0">​}</​span><​span class="​br0">​}</​span><​span class="​sy4">;</​span>​ 
 +        epoll_ctl<​span class="​br0">​(</​span>​epollDescr,​ EPOLL_CTL_ADD,​ serverSock, <span class="​sy3">&​amp;</​span>​ee<​span class="​br0">​)</​span><​span class="​sy4">;</​span>​ 
 +    <span class="​br0">​}</​span></​span>​ 
 +    <span style="​opacity:​0.66">​~Server<​span class="​br0">​(</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span></​span>​ 
 +<span style="​background-color:#​8001"​ title="​W obsłudze zdarzenia – żądanego POLLIN bądź błędu (którego obsługa tu jest pominięta) – przyjmowane jest nowe połączenie i tworzony obiekt z klasy Client, który sam dodaje obsługiwane przez siebie gniazdo do epolla"> ​   <span class="​kw4">​void</​span>​ handle<​span class="​br0">​(</​span>​epoll_event <span class="​sy3">&​amp;</​span><​span class="​br0">​)</​span>​ <span class="​br0">​{</​span>​ 
 +        <span class="​kw4">​int</​span>​ cliFd <span class="​sy1">​=</​span>​ accept<​span class="​br0">​(</​span>​serverSock,​ <span class="​nu0">​0</​span>,​ <span class="​nu0">​0</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span>​ 
 +        <span class="​kw3">​new</​span>​ Client<​span class="​br0">​(</​span>​epollDescr,​ cliFd<​span class="​br0">​)</​span><​span class="​sy4">;</​span>​ 
 +    <span class="​br0">​}</​span></​span>​ 
 +<span class="​br0">​}</​span><​span class="​sy4">;</​span>​
  
-std::list<Clientclients; +<span style="​opacity:0.66">​<span class="​kw4"​>int</​span>​ main<​span class="​br0">​()</​span>​ <span class="​br0">​{</​span></​span>​ 
-int epollfd; +    ... 
- +    <​span class="​kw4">​int</​span>​ epollDescr <span class="​sy1">​=</​span>​ epoll_create1<​span class="​br0">​(</​span><​span class="​nu0">​0</​span><​span class="​br0">​)</span><​span class="​sy4">;<​/span> 
-void newClientArrived(){ +    ​Server srv<span class="​br0">​(</​span>​epollDescrport<​span class="​br0">​)</​span><​span class="​sy4">​;</span> 
-   int sock = accept(... +    <​span class="​kw1">​while</​span>​ <span class="​br0">​(</​span><​span class="​nu0">​1</​span><​span class="​br0">​)</​span>​ <span class="​br0">​{</​span>​ 
-   clients.emplace_back(sock);​ +        epoll_event ee<span class="​sy4">​;</​span>​ 
-   ​epoll_event ee {EPOLLIN, {.ptr=&​clients.back()}}; // referencje do elementów listy są ważne +        epoll_wait<span class="​br0">​(</​span>​epollDescr<span class="​sy3">​&amp;</​span>​ee, <span class="​nu0">​1</​span>​<span class="​sy2">​-</​span><​span class="​nu0">​1</​span><​span class="​br0">​)</​span><​span class="​sy4">;</​span>​ 
-   epoll_ctl(epollfd, EPOLL_CTL_ADDsock, &ee);     /do usunięcia wskazywanego elementu +        <​span style="​background-color:#​0001"​ title="​Wartość .data.ptr zawsze wskazuje na obiekt z klasy (dziedzicząej po) Handler, z metodą '​handle'​ do obsługi zdarzenia"><​span class="​br0">​(</​span><​span class="​br0">​(</​span>​Handler ​<span class="​sy2">​*</​span><​span class="​br0">​)</​span>​ee.<span class="​me1">​data</​span>​.<span class="​me1">​ptr</​span><​span class="​br0">​)</​span><​span class="​sy2">​-</​span><​span class="​sy1">&​gt;</​span>​handle<​span class="​br0"​>(</​span>​ee<span class="​br0">​)</​span><​span class="​sy4">​;</​span></​span>​ 
-   ... +    <​span class="​br0">​}</​span>​ 
-+<span style="​opacity:​0.66"><​span class="​br0">​}</​span></​span>​ 
-    +</​pre>​ 
-int main(){ +</html>
-   ... +
-   epoll_event ee; +
-   while(epoll_wait(epollfd, &ee, 1, -1)) +
-     ​((Handler*)ee.data.ptr)->​handleEvent(ee.events); +
-+
-</code>+
 ++++ ++++
  
-//Zadanie ​4.// Powtórz Zadanie 1, ale tym razem jako jednowątkowy program wykorzystujący mechanizm epoll.+~~Zadanie.#~~ Powtórz Zadanie 1, ale tym razem jako jednowątkowy program wykorzystujący mechanizm epoll. 
 +\\ 
 +(Możesz skorzystać z {{:​sk2:​tcp_client_template.cpp|przykładowego kodu klienta}})
  
-//Zadanie ​5.// Napisz jednowątkowy serwer czatu używając ''​poll''​ lub ''​epoll_wait''​.+~~Zadanie.#~~ Napisz jednowątkowy serwer czatu używając ''​poll''​ lub ''​epoll_wait''​. 
 +\\ 
 +(Możesz skorzystać z {{:​sk2:​tcp_server_template.cpp|przykładowego kodu serwera}})
sk2/sockets_concurrency.1699529445.txt.gz · ostatnio zmienione: 2023/11/09 12:30 przez jkonczak