]> rtime.felk.cvut.cz Git - edu/osp-wiki.git/blob - cviceni/server.mdwn
(no commit message)
[edu/osp-wiki.git] / cviceni / server.mdwn
1 [[!meta title="Obsluha mnoha klientů"]]
2
3 [[!toc]]
4
5 Cíl
6 ===
7
8 Hlavním cílem této úlohy je implementovat jednoduchou serverovou
9 aplikaci a optimalizovat její výkon tak, aby zvládala obsluhu velkého
10 množství klientů a požadavků. **Pro implementaci serveru si můžete
11 zvolit jakoukoli platformu** (HW, OS, programovací jazyk, framework,
12 …).
13
14 Vedlejší cíle jsou naučit se pracovat s dokumentací a zdrojovými kódy
15 použitých platforem (zejména těch založených na open source softwaru),
16 aplikace znalostí nabytých na přednáškách a získání přehledu o
17 výkonnosti jednotlivých platforem.
18
19 Zadání úkolu
20 ============
21
22 Vytvořte serverovou aplikaci komunikující protokolem [HTTP][], která
23 bude sloužit k počítání unikátních slov v datech zaslaných klienty. Na
24 server jsou kladeny následující požadavky:
25
26 - Klienti posílají data pomocí [metody POST][POST] s cestou
27   `/osp/myserver/data`. Data jsou ve formátu čistého textu
28   (text/plain) v kódování UTF-8.
29 - Server obsahuje "čítač jedinečných slov". Při spuštění serveru je
30   tento čítač roven 0.
31 - Server si vede evidenci o slovech zaslaných v jednotlivých
32   požadavcích a pro každé nové slovo, které ještě nemá v evidenci
33   zvýší čítač jedinečných slov o jedna.
34 - Na požadavek [GET][] s cestou `/osp/myserver/count` server odpoví
35   aktuální hodnotou čítače jedinečných slov a tento čítač vynuluje.
36   Hodnota se přenáší jako dekadické číslo v UTF-8 kódování.
37 - Server musí zvládnou obsluhovat velké množství (cca 100) současně
38   připojených klientů.
39
40 [HTTP]: http://tools.ietf.org/html/rfc2616
41 [POST]: http://tools.ietf.org/html/rfc2616#section-9.5
42 [GET]: http://tools.ietf.org/html/rfc2616#section-9.3
43
44 Příklad
45 -------
46
47 Předpokládejme, že náš server běží na adrese 127.0.0.1 (t.j.
48 localhost) na portu 8000. Použijeme program `curl` k posílání
49 požadavků serveru:
50
51     curl 127.0.0.1:8000/osp/myserver/data --data-binary "první pokus"
52     curl 127.0.0.1:8000/osp/myserver/data --data-binary "druhý pokus"
53     curl 127.0.0.1:8000/osp/myserver/count --output -
54
55 Výstupem posledního příkazu bude řetězec "3". Místo posledního příkazu
56 můžete použít i webový prohlížeč nasměrovaný na adresu
57 <http://127.0.0.1:8000/osp/myserver/count>.
58
59 Výkon serveru
60 -------------
61
62 Výkon serveru bude měřen testovacím programem, který bude serveru
63 posílat větší množství dat a poté se zeptá na aktuální hodnotu čítače
64 jedinečných slov. Bude se měřit celkový čas od odeslání prvního
65 požadavku typu POST do příjmu hodnoty čítače jedinečných slov.
66
67 Akceptována budou řešení jejichž **celkový čas bude dvakrát menší**
68 než čas naměřený s níže uvedeným ukázkovým serverem bežícím na školním
69 počítači v laboratoři.
70
71 Ukázkový server
72 ===============
73
74 Zde uvádíme jednoduchý server napsaný v jazyce Python, který splňuje
75 výše uvedené požadavky (kromě výkonnosti). Můžete ho použít jako
76 referenci či startovací bod pro vaší implementaci.
77
78 [[!format py """
79 #!/usr/bin/python3
80
81 from http.server import HTTPServer, BaseHTTPRequestHandler
82
83 words = {}
84
85 class OSPHTTPHandler(BaseHTTPRequestHandler):
86     def do_POST(self):
87         global words
88         if self.path == "/osp/myserver/data":
89             length = int(self.headers.get('Content-Length'))
90             text = self.rfile.read(length).decode("utf-8")
91             for word in text.split():
92                 words[word] = 1;
93             self.send_response(204) # No Content
94             self.end_headers()
95         else:
96             self.send_response(404)
97             self.end_headers()
98
99     def do_GET(self):
100         global words
101         if self.path == "/osp/myserver/count":
102             self.send_response(200)
103             self.send_header("Content-type", "text/plain")
104             self.end_headers()
105             self.wfile.write(str(len(words)).encode())
106             words = {}
107         else:
108             self.send_response(404)
109             self.end_headers()
110
111 httpd = HTTPServer(('', 8000), OSPHTTPHandler)
112 print("Listening on port", httpd.server_port)
113 httpd.serve_forever()
114 """]]
115
116 Testování a měření výkonu
117 =========================
118
119 Pro testování použijte
120 [odevzdávací systém](https://rtime.felk.cvut.cz/osp/cviceni/server/tester/),
121 kam zadáte informace o vašem serveru a můžete ho nechat otestovat. Pět
122 nejlepších studentů dostane 1 až 5 bonusových bodů.
123
124 **Odevzdávací systém běží momentálně v testovacím provozu.** Je možné,
125 že naměřené hodnoty budou horší, než jaké lze z vašeho serveru
126 "vymáčknout".
127
128 Kromě odevzdávacího systému můžete použít i program
129 `osp-server-tester`, který je nainstalován školních počítačích. Pro
130 testování ukázkového serveru spusťte program následovně:
131
132     osp-server-tester localhost 8000
133
134 Pokud testovací program spustíte následovně
135
136     osp-server-tester localhost 8000 --more
137
138 ukázkový server bude přetížen a čas od času bude klienty odmítat.
139 Takže prvním krokem vašeho řešení může být zjištění příčiny tohoto
140 chování a její napravení.