Pracovat v sítovém prostředí lze na nižší úrovni, k tomu nám slouží například třídy jmenného prostoru System.Net.Sockets. Zde musíme dbát na to, zda je napojen socket a posléze tento socket zpracovat. Dá se ale pracovat i bez potřeby práce na nižší úrovni. Můžeme využívat třídy, které se postarají o navázání spojení a vyřízení požadavku.
Na následujícím příkladu si vytvoříme jednoduchého webového klienta s pomocí tříd WebRequest a WebResponse.
using System.Net; using System.IO; ... // vytvoreni get pozadavku na cilovou uri WebRequest request = WebRequest.Create("www.cs.vsb.cz"); // ziskani odezvy na pozadavek WebResponse response = request.GetResponse(); // vytvoreni proudu z odezvy Stream receieveStream = response.GetResponseStream(); // vytvoreni ctenare proudu StreamReader sr = new StreamReader(receiveStream, Encode.UTF-8) // vytvoreni a nacteni bufferu pro nacitana data Char[] read = new Char[256]; int count = sr.Read(read, 0, 256); // zpracovani ziskanych dat while(count > 0) { string str = new string(read, 0, 256); System.Console.WriteLine(str); count = sr.Read(read, 0, 256); } |
Jak je vidět z ukázky kódu, stačí vytvořit instance tříd WebRequest, WebResponse, Stream a StreamReader a můžeme zpracovávat data získaná z webového požadavku.
Kompletní projekt na demonstraci tříd WebRequest a WebResponse s pomocí grafického rozhraní je k dispozici zde. |
Předcházející příklad se dá vytvořit jak složitěji, tak o něco jednodušeji. A to s pomocí třídy WebClient, která pracuje na vyšší úrovni než WebRequest a WebResponse.
using System; using System.Net; using System.Text; class MyWebClient { public static void Main(string[] args) { WebClient wc = new WebClient(); byte[] buffer = wc.DownloadData(args[0]); string content = Encoding.ASCII.GetString(buffer); Console.WriteLine(content); } } |
Vidíme, že není třeba vytvářet vlastní webové klienty. S pomocí typu WebClient můžeme provádět operace jako download a upload dat či souborů, získávat informace o hlavičkách apod.
Tento přklad je možno k vyzkoušení stáhnout zde. |
Jak jsme se zmínili v odstavci 2.2, lze webového klienta (a síťovou práci celkově) sestrojit pomocí "delšího kódu" ručně. To si ukážeme nyní. Pro podporu protokolu TCP nám dobře poslouží třídy (System.Net.) TcpClient a TcpListener.
TcpListener je vytvořen pro naslouchání příchozích konekcí a odesílání odpovědí instancí typu Socket odpovídající požadavku připojení. Použivá se tedy na straně serveru. TcpClient slouží k připojení ke vzdálenému počítači (hostu). Po vytvoření připojení lze využít proudu (NetworkStream) pro posílání/příjem dat.
Nyní si pro změnu ukážeme náznak jednoduchého HTTP serveru vyřizujícího požadavek GET.
Pokud chceme realizovat HTTP server, je třeba znát IP adresu a port, na který se budou posílat data. Pro naše účely použijeme místní počítač (adresa 127.0.0.1) a port si zvolíme jiný než 80, např. 5050. Vytvoříme tedy instanci třídy TcpListener, která bude na dané adrese naslouchat.
using System; using System.Net; using System.Net.Sockets; ... TcpListener myListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 5050); Socket socket; // zacina se naslouchat na dane IP adrese a portu myListener.Start(); // navazani spojeni a vyrizovani prichozich socketu while(true) { socket = myListener.AcceptSocket(); if(socket.Connected) { // vytvoreni bufferu pro ziskana data Byte[] received = new Byte[1024]; // prijimani dat - pozadavku int i = socket.Receive(received, received.Length, 0); // prevod bytu na retezec string request = System.Text.Encoding.ASCII.GetString(received); /// vytvoreni bufferu pro naplneni daty k odeslani Byte[] dataToSend = new Byte[...] // .... zpracovani prichoziho pozadavku .... // .... ziskani souboru k odeslani .... // odeslani dat klientu socket.Send(dataToSend, dataToSend.Length, 0); } } ... |
Po vytvoření "naslouchače požadavků" se čeká (v nekonečném cyklu) na příchozí požadavek. V momentě, kdy nejaký klient zažádá na adrese 127.0.0.1 a portu 5050 o spojení, to se vytvoří. Pak se vytvoří přijímací buffer a získaná data se načtou pomocí metody Socket.Receive(). Následně se získaná data převedou na řetězec a ten se může zpracovat jako text obsahující podmínky požadavku.
Jakmile získáme z požadavku název souboru, který se má zobrazit (poslat), můžeme provést jeho načtení (binární) a naplnění bufferu připraveného pro odeslání. Odeslání provedeme metodou Socket.Send().
Samozřejmě takto vytvořený server by nebyl velice užitečný. V jednu chvíli by mohl zpracovat a vyřídit pouze jeden požadavek, v té chvíli by byl nedostupný pro ostatní klienty. Toto se dá vyřešit s pomocí vláken, kdy bychom s každým příchozím požadavkem spouštěli metodu tento požadavek vyřizující.
Příklad s HTTP serverem je k dispozici k nahlédnutí a vyzkoušení zde. |