2. Webový klient

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.

2.1. Třídy WebRequest a WebResponse

Na následujícím příkladu si vytvoříme jednoduchého webového klienta s pomocí tříd WebRequest a WebResponse.

[ukázka kódu]
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.

[příklad ke stažení]

Kompletní projekt na demonstraci tříd WebRequest a WebResponse s pomocí grafického rozhraní je k dispozici zde.

2.2. Třída WebClient

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.

[ukázka kódu]
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.

[příklad ke stažení]

Tento přklad je možno k vyzkoušení stáhnout zde.

2.3. Třída TcpClient, TcpListener

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.

[ukázka kódu]
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 ke stažení]

Příklad s HTTP serverem je k dispozici k nahlédnutí a vyzkoušení zde.