Klientská část je klientem serverové aplikace. Různá architektonická řešení používaná při implementaci víceuživatelských databází. stručný přehled subd. servery. Základy serveru

V tomto příkladu vyvineme jednoduchý server a jednoduchý klientský program, kteří spolu vedou „nevolný“ dialog. Klienta postavíme podle technologie Windows Forms a server - Služba Windows . Server bude mít připravenou sadu označených odpovědí, bude čekat na označené požadavky od klientů a odpovídat na ně příslušnými zprávami. To nás nastaví na vytvoření ještě složitějšího systému – prohlížení vzdálených výkresů z databáze, kterým se budeme věnovat později.

Vytvoření klienta

Začněme s klientský program, který může běžet v mnoha případech ("http://msdn.microsoft.com/ru-ru/library/system.net.sockets.tcplistener.accepttcpclient.aspx")


Tabulka 19.7.
Živel Vlastnictví Význam
Formulář Text Klient
Velikost 300; 300
Seznam (Název) seznam
Dok Horní
Písmo Arial; 12pt
Položky
  1. Ahoj!
  2. Lelík
  3. Co se děje
  4. Dáme si dneska?
  5. Tak ahoj!
SelectionMode Jeden
Velikost 292; 119
Knoflík (Název) btnOdeslat
Automatická velikost Skutečný
Písmo Arial; 10pt
Umístění 96; 127
Velikost 101; 29
Text Poslat
Textové pole (Název) Textové pole
Dok Dno
Umístění 0; 162
Víceřádkový Skutečný
Posuvníky Vertikální
Velikost 292; 105

Odpočinek požadovaná nastavení Formulářové prvky přidáme programově.

pomocí systému; pomocí System.Collections.Generic; pomocí System.ComponentModel; pomocí System.Data; pomocí System.Drawing; pomocí System.Text; pomocí System.Windows.Forms; // Další jmenné prostory pomocí System.IO; pomocí System.Net; pomocí System.Net.Sockets; pomocí System.Threading; jmenný prostor SimpleClient ( veřejná částečná třída Form1: Form ( int port = 12000; String hostName = "127.0.0.1"; // místní klient TcpClient = null; // Odkaz na klienta public Form1() ( InitializeComponent(); // Vyberte první položka seznamu listBox.SelectedIndex = 0; listBox.Focus(); // Kontextová nabídka pro vymazání TextBox ContextMenuStrip contextMenu = new ContextMenuStrip(); .MouseDown += new MouseEventHandler(item_MouseDown // Odeslání požadavku a přijetí odpovědi private void btnSubmit_Click(odesílatel objektu, EventArgs e) ( if (listBox.SelectedIndices.Count == 0) ( MessageBox.Show ("Vybrat zprávu"); ); return; ) try ( // Vytvořte klienta připojeného k serveru client = new TcpClient(hostName, port); // Nastavte velikosti schránek sami (Volitelné!) client.SendBufferSize = client.ReceiveBufferSize = 1024 ; ) catch ( MessageBox.Show("Server není připraven!"); vrátit se;

) // Zapište požadavek do protokolu AddString("Client: " + listBox.SelectedItem.ToString()); // Vytvoření streamů NetworkStream připojených k serveru NetworkStream streamIn = client.GetStream(); NetworkStream streamOut = client.GetStream(); StreamReader readerStream = new StreamReader(streamIn); StreamWriter WriterStream = new StreamWriter(streamOut); // Odešle požadavek na server writeStream.WriteLine(listBox.SelectedItem.ToString()); spisovatelStream.Flush(); // Přečtení odpovědi String receiverData = readerStream.ReadLine(); // Zapíše odpověď do protokolu AddString("Server: " + receiverData); // Zavřete spojení a streamy, pořadí není důležité client.Close(); spisovatelStream.Close(); readerStream.Close(); ) // Přidání řádku, když je TextBox povolen ve víceřádkovém režimu private void AddString(Řetězec) ( StringBuilder sb = new StringBuilder(textBox.Text); StringWriter sw = new StringWriter(sb); sw.WriteLine(řádek); textBox .Text = sw.ToString() // Vymazání seznamu pomocí kontextové nabídky void item_MouseDown(object sender, MouseEventArgs e) ( textBox.Clear(); listBox.Focus(); ) ); NetworkStream a zabalte je do obalů, které jsou vhodné pro ovládání čtení/zápisu. Výměna se serverem je zobrazena v protokolu Textové pole. Pro vymazání protokolu byla dynamicky vytvořena kontextová nabídka.

Třída TcpClient, který jsme použili v kódu, je na vysoké úrovni (a zjednodušený) obal kolem soketu (třída Zásuvka). Pokud je vyžadováno ovládání soketu nižší úrovně (podrobnější), pak je odkaz na něj uložen ve vlastnosti TcpClient.Client. Ale protože je tato vlastnost chráněna ( chráněný), pak k němu lze přistupovat pouze z derivátu TcpClient třída.

Pokud nyní aplikaci spustíte SimpleClient, pak to bude fungovat, ale když se pokusíte něco odeslat na server, zobrazí se zpráva, že server není připraven. Zatím neexistuje žádný server, pojďme si ho vytvořit.

Vytvoření serveru

Udělejme program serveru rezidentní podle šablony Služba Windows, jak jsme to udělali v předchozím příkladu, i když to můžete udělat pomocí rozhraní, hlavní věcí je, že by mělo být spuštěno v jediné kopii na místní počítač. Pokud je serverový program součástí globální sítě, pak s použitým IP a měl by to být jediný port v této síti. Proto použití sítě IP Pro globální síť musíte získat oprávnění.



pomocí systému; pomocí System.ComponentModel; pomocí System.Configuration.Install; pomocí System.ServiceProcess; jmenný prostor SimpleServer ( // Během instalace sestavení by měl být instalační program nazýván veřejnou částečnou třídou Installer1: Installer ( private ServiceInstaller serviceInstaller; private ServiceProcessInstaller serviceProcessInstaller; public Installer1() ( // Vytvoření nastavení pro Service serviceInstaller = new ServiceInstaller(); serviceProcessInstaller = new ServiceProcessInstaller( ); // Název služby pro počítač a uživatele serviceInstaller.ServiceName = "SimpleServerServiceName" = "SimpleServer" = ServiceStartMode.Manual; být spuštěn this.serviceProcessInstaller.Account = ServiceAccount.LocalService; this.serviceProcessInstaller.Password = null; this.serviceProcessInstaller.Username = null // Přidat nastavení do kolekce aktuálního objektu this.Installers.AddRange(new Installer, serviceInstaller, serviceProcessInstaller ) ));

pomocí systému; pomocí System.Collections.Generic; pomocí System.Text; // Další jmenné prostory pomocí System.IO; pomocí System.Net; pomocí System.Net.Sockets; pomocí System.Threading; pomocí System.ServiceProcess; pomocí System.Collections; jmenný prostor SimpleServer ( třída Service1: ServiceBase ( TcpListener server = null; // Odkaz na server int port = 12000; String hostName = "127.0.0.1"; // místní IPAddress localAddr; String odpovědi = ( "1. Kdo jste?" , "2. Ahoj, Leliku!", "3. Nejlepší ze všech!", "4. Samozřejmě naplno", "5. Uvidíme se večer // Constructor public Service1() (); localAddr = IPAddress.Parse( hostName);// Převést na jiný formát Thread = new Thread(ExecuteLoop).IsBackground = true.Start();/; / Vytvořte server posluchače server.Start();// Spusťte server String data; Nekonečný koloběh naslouchání klientům při (true) ( ​​pokud (!server.Pending()) // Fronta požadavků je prázdná pokračovat; TcpClient client = server.AcceptTcpClient(); // Aktuální klient // Nastavíme velikosti schránek sami (Volitelně!) // Ve výchozím nastavení jsou obě vyrovnávací paměti nastaveny na 8192 bajtů o velikosti client.SendBufferSize = client.ReceiveBufferSize = 1024 // Připojte NetworkStream a načtěte jej do shellů NetworkStream streamIn = client.GetStream(); NetworkStream streamOut = client.GetStream(streamIn) StreamWriter spisovatelStream = new StreamWriter(streamOut) // Přečtení dat požadavku int index if (int.TryParse(); data.Substring(0, data.IndexOf(" ")), out index)) data = odpovědi; else data = data.ToUpper(); spisovatelStream.WriteLine(data); spisovatelStream.Flush(); // Zavřete spojení a streamy, pořadí není důležité client.Close(); readerStream.Close(); spisovatelStream.Close(); ) ) catch (SocketException) ( ) nakonec ( // Zastavení serveru server.Stop(); ) ) ) )

Chcete-li odeslat data a přijmout odpověď, klientská aplikace vytvoří obousměrný soket (nebo dva jednosměrné), ve kterém specifikuje adresu připojení k soketu jiné serverové aplikace. Pokud je spojení navázáno (server běží), pak klientská aplikace připojí síťový proud k soketu NetworkStream a jeho prostřednictvím přenáší a přijímá data.

Na druhé straně připojení je server TcpListener poslouchá v nekonečné smyčce fronta připojení s klienty. Pokud se k němu připojil nějaký klient ( server.Pending()!=false), pak server načte tohoto klienta pomocí AcceptTcpClient()- vytvoří soket pro příjem/vysílání s připravenou návratovou adresou, vytvoří obousměrný tok (nebo dva jednosměrné), poté přečte požadavek a odešle odpověď.



Vezměte prosím na vědomí, že pokud kód našeho serverového programu není zabalen do samostatného vlákna Vlákno(prováděcí vlákno), pak operační systém tento program v okně služeb nespustí (zkuste to!). Důvodem je to v kódu metody ExecuteLoop() Server používá nekonečnou smyčku naslouchání frontě požadavků klientů. Pokud je tato smyčka ponechána v hlavním vláknu provádění ( Vlákno) aplikace, jednoduše přejde do smyčky a nebude možné ji normálně ukončit. Kód se smyčkou proto umístíme do samostatného vlákna (vlákna) a uděláme mu pozadí tak, aby se uzavíralo spolu s hlavním aplikačním vláknem (vláknem serveru).

Důležitá poznámka

Tok NetworkStream je oboustranná pevná délka. Metoda GetStream() pouze naváže adresové spojení mezi klientskými a serverovými sokety. Jeho skutečná délka je ale určena zprávou od odesílající strany. Pro příjem/odesílání můžete použít jedno vlákno, ale pak by délka zprávy odeslané serverem neměla přesáhnout délku zprávy, kterou obdržel od klienta (málem jsem přišel o oko!). Proto používáme dva toky na každé straně pro samostatný jednosměrný přenos mezi dvěma uzly síťového připojení.

Příklad 3. Klient-server aplikace pro prohlížení obrázků z databáze

V předchozím jednoduchém příkladu jsme se seznámili (trochu) s principy tvorby síťových aplikací. Nyní pojďme stavět další složitý příklad, když klient požaduje obrázky a server je načte z úložiště a odešle klientovi. V Cvičení 7 Vyvinuli jsme tři různá úložiště obrázků a tři programy pro prohlížení. V tomto příkladu použijeme databázi Obrázky.my2.mdb S hotové výkresy a na jejím základě vytvoříme síťovou aplikaci (pro ty, kteří ještě neudělali Cvičení 7, DB je přiložena v katalogu Zdrojová data).

Budování klienta

Pro klienta sestavíme okenní aplikaci jako např WPF S uživatelské rozhraní, částečně zapůjčeno z Příklad 6 Cvičení 7.


Server není připraven, čekejte prosím! Snažíme se kontaktovat omluvám se za nepříjemnost...

Pro zobrazení úvodní obrazovky s textem, že server není připraven, jsme použili prvek Viewbox, do kterého byl umístěn další prvek okraj s textovým obsahem. Tato „zahrada“ vám umožní zvětšit spořič obrazovky v poměru k velikosti okna. Nicméně zavedení prvku Viewbox začíná znatelně zpomalovat překreslování rozhraní při pohybu okna, protože se snaží neustále přepočítávat měřítka svých podřízených prvků. Názvy jsme přiřadili pouze těm prvkům rozhraní, které budeme spravovat v procedurálním kódu.

pomocí systému; pomocí System.Collections.Generic; pomocí System.Text; pomocí System.Windows; pomocí System.Windows.Controls; pomocí System.Windows.Data; pomocí System.Windows.Documents; pomocí System.Windows.Input; pomocí System.Windows.Media; pomocí System.Windows.Media.Animation; pomocí System.Windows.Media.Imaging; pomocí System.Windows.Shapes; // Další jmenné prostory pro Stream using System.IO; pomocí IO = System.IO; // Alias ​​pro adresování Path pomocí System.Windows.Threading; // Pro DispatcherTimer // Další jmenné prostory pro Socket //pomocí System.Net; pomocí System.Net.Sockets; pomocí System.Collections; // Seznam jmenný prostor PicturesClientDB ( veřejná částečná třída Window1: Window ( int port = 12000; String hostName = "127.0.0.1"; // local TcpClient client = null; // Klientský odkaz String sendMessage = "!!!GetNames!!!"; / / Požadavek na seznam (záludný) Oddělovač znaků = ( "#" ); // Převedení odpovědi na pole názvů Časovač Dispatcher // Konstruktor public Window1() ( InitializeComponent(); // Vytvořit a spustit časovač časovače = new DispatcherTimer(); timer.Tick += new EventHandler(timer_Tick.Interval = TimeSpan.FromSeconds(1) // Zahájí volání serveru void timer_Tick(object); odesílatel, EventArgs e) ( Execute(listBox); ) private void listBox_SelectionChanged(odesílatel objektu, SelectionChangedEventArgs e) ( Execute((ListBox)sender); ) void Execute(ListBox lst) ( // Vyplňte seznam názvy obrázků zkuste ( / / Pokud je server dostupný, vytvořte klienta klienta = new TcpClient(název_hostitele, port) catch ( // Server není připraven, spusťte časovač a ukončete, pokud (Prompt.Visibility != Visibility.Visible) ( Prompt.Visibility = Viditelnost.Viditelný; časovač.Start(); ) vrátit se; ) switch (sendMessage) ( case "!!!GetNames!!!": // Příjem a spojení názvů obrázků se seznamem lst.ItemsSource = GetNames(); // Vyberte první prvek seznamu pro volání SelectionChanged lst .SelectedIndex = 0; sendMessage = "" break; .Stop() / / Přijetí obrázku a jeho zobrazení uživateli pomocí štětce String name = lst.SelectedValue.ToString() BitmapImage bi = new BitmapImage(); v paměťovém proudu bi.StreamSource = new MemoryStream (GetPicture(name) bi.EndInit(Picture.picture.ImageSource = bi); přestávka; ) ) private String GetNames() ( Názvy řetězců; // Vytváření proudů síťových připojení StreamReader readerStream = new StreamReader(client.GetStream()); StreamWriter WriterStream = new StreamWriter(client.GetStream()); // Odeslat požadavek na serverwriteStream WriteLine(sendMessagewriteStream.Flush(); // Přečtení odpovědi String receiverData = readerStream.ReadLine( names = receiverData.Split(separator); a streamy, pořadí není důležité clientStream.Close() návrat jména ) Byte GetPicture(String name) ( // Vytvořit streamy síťového připojení readerStream = client.GetStream(); (klient. GetStream() // Odeslání požadavku na server writeStream.WriteLine(name writeStream.Flush() // Přečtení odpovědi // ReceiveBufferSize - velikost vyrovnávací paměti pro příchozí data // SendBufferSize - velikost vyrovnávací paměti pro); Seznam odchozích dat seznam = nový seznam< count; i++) list.Add(bytes[i]); // Преобразуем в массив результата bytes = new Byte; list.CopyTo(bytes); // Закрываем соединение и потоки, порядок неважен client.Close(); writerStream.Close(); readerStream.Close(); return bytes; } } // Для привязки к ресурсу class Pictures { // Поле public static ImageBrush picture = new ImageBrush(); static Pictures() { // Дежурный рисунок заставки picture.ImageSource = new BitmapImage(new Uri(@"flower2.jpg", UriKind.Relative)); picture.Stretch = Stretch.Fill; picture.Opacity = 1.0D; } // Привязываемое в интерфейсе свойство public static ImageBrush Picture { get { return picture; } } } }

(client.ReceiveBufferSize) // Přírůstková kapacita Byte bytes = new Byte; // Velikost vyrovnávací paměti soketu int pocet = 0; // Části příchozích dat while ((count = readerStream.Read(bytes, 0, bytes.Length)) != 0) for (int i = 0; i Upozorňujeme, že při zobrazování obrázků jsme opustili tradiční prvek obraz , jak bylo provedeno v předchozím cvičení. A oni si pro změnu počínali zcela netradičně (v turečtině). Nyní zobrazíme kresby štětcem ImageBrush okraj na pozadí obdélníku prostřednictvím předmětu k němu připojeného obrázky


. Samozřejmě, v životě je nepravděpodobné, že budete muset tímto způsobem zvrhnout, ale tato možnost se může někde hodit. Úvodní obrazovka se objeví, jakmile je zjištěna skutečnost, že server chybí nebo je zastaven. A po zjištění serveru spořič obrazovky zmizí. Tento mechanismus bude fungovat okamžitě díky systémový časovač

. Zatím však neexistuje žádný server a měl by být vytvořen.
  • Budování databázového serveru jako služby tým Soubor/Přidat/Nový projekt NetworkStream přidat do roztoku nový projekt pojmenovaný PicturesServerDB Služba Windows


pomocí systému; pomocí System.Collections.Generic; pomocí System.ComponentModel; pomocí System.Data; pomocí System.Diagnostics; pomocí System.ServiceProcess; pomocí System.Text; // Další jmenné prostory pro ADO.NET pomocí System.Data.OleDb; pomocí System.Data.Common; // Další jmenné prostory pomocí System.IO; pomocí System.Net; pomocí System.Net.Sockets; pomocí System.Threading; pomocí System.Collections; jmenný prostor PicturesServerDB ( veřejná částečná třída Service1: ServiceBase ( int port = 12000; String hostName = "127.0.0.1"; // místní IPAddress localAddr; TcpListener server = null; // Odkaz na server Oddělovač řetězce = "#"; // Oddělovač jména v řádku odpovědi String connectionString // Řetězec připojení k databázi public Service1() ( // Extrahujte řetězec připojení k databázi ze souboru App.config do pole connectionString = System.Configuration.ConfigurationManager. ConnectionStrings["PicturesDB"].ConnectionString. ; / / Převést IP do jiného formátu localAddr = IPAddress.Parse (název_hostitele) // Spustit v novém vláknu (vlákně) vlákno = new vlákno.IsBackground = true; ( try ( server = new TcpListener(localAddr, port);// Vytvořte server-listener server.Start();// Spusťte server // Nekonečná smyčka naslouchání klientům, zatímco (true) ( ​​​​ // Zkontrolujte fronta připojení if (!server .Pending()) // Fronta požadavků je prázdná pokračovat; TcpClient client = server.AcceptTcpClient();// Aktuální klient // Vytvořit proudy síťového připojení StreamReader readerStream = new StreamReader(client.GetStream()); NetworkStream streamOut = client.GetStream(); StreamWriter WriterStream = new StreamWriter(streamOut); // Přečtení příkazu klienta String receiverData = readerStream.ReadLine(); // Rozpoznejte a spusťte přepínač (receiverData) ( case "!!!GetNames!!!":// Odešlete jména oddělená oddělovačem String names = GetNames();writeStream.WriteLine(names); // UsewriteStream.Flush through shell (); default:// Odeslat obrázek Byte bytes = GetPicture(receiverData)(bajty, 0, bytes.Length) na tom nezáleží client.Close(); readerStream.Close(); spisovatelStream.Close(); ) ) nakonec ( // Zastavení serveru server.Stop(); ) ) // Získání názvů obrázků z databáze a jejich zabalení do jednoho řádku pro odeslání klientskému řetězci GetNames() ( // Vytvořte a nakonfigurujte infrastrukturu ADO. NET OleDbConnection conn = new OleDbConnection(connectionString); OleDbCommand cmd = new OleDbCommand("SELECT FileName FROM MyTable"); cmd.Connection = připojení; conn.Open(); // Načtení názvů obrázků OleDbDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection); // Vytvoří řetězec odchozích dat StringBuilder sb = new StringBuilder(); foreach (záznam DbDataRecord ve čtečce)// Ekvivalent ke čtení reader.Read() sb.Append(((string)record["NázevSouboru"]).Trim() + oddělovač); // Spojení zde uzavře samotný objekt DataReader po načtení všech dat // v souladu s konvencí při jeho vytvoření CommandBehavior.CloseConnection // Odebere extra poslední znak oddělovače sb.Replace(separator, String.Empty, sb.ToString(). LastIndexOf(separator ), separator.Length); return sb.ToString(); ) // Načtení samotného obrázku z databáze k odeslání klientovi bajt GetPicture(String name) ( // Vytvořte a nakonfigurujte infrastrukturu ADO.NET OleDbConnection conn = new OleDbConnection(); conn.ConnectionString = connectionString; // Vytvořte a nakonfigurovat objekt příkazu parametrizovaný názvem obrázku OleDbCommand cmd = new OleDbCommand() cmd.Connection = conn; .Add(new OleDbParameter()) cmd.Parameters.Value = name;// Název obrázku OleDbDataAdapter adapter = new OleDbDataAdapter(cmd // Získání obrázku z databáze DataTable table = new DataTable( ); bytes = (byte)table.Rows["Obrázek"] // Připojení k obrázku return bytes;

typ

Aplikace klient-server na TCP stream soketu

Následující program vytvoří server, který přijímá požadavky na připojení od klientů. Server je sestavován synchronně, proto je provádění vláken blokováno, dokud server nesouhlasí s připojením ke klientovi. Tato aplikace demonstruje jednoduchý server reagující na klienta. Klient ukončí spojení odesláním zprávy na server .

TCP Server

Vytvoření struktury serveru je znázorněno na následujícím funkčním schématu:

Tady úplný kód Programy SocketServer.cs:

// SocketServer.cs using System; pomocí System.Text; pomocí System.Net; pomocí System.Net.Sockets; jmenný prostor SocketServer ( class Program ( static void Main(string args) ( // Nastavení místního koncového bodu pro soket IPHostEntry ipHost = Dns.GetHostEntry("localhost"); IPAddress ipAddr = ipHost.AddressList; IPEndPoint ipEndPoint = new IPEndPoint(ip 11000 ); // Vytvořte soket Tcp/Ip sListener = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp // Přiřaďte soket k místnímu koncovému bodu a poslouchejte příchozí sokety try ( sListener.Bind(ipEndPoint); ); sListener(10) // Zahájení naslouchání připojení, zatímco (true) ( ​​​​Console.WriteLine("Čekání na připojení na portu (0)", ipEndPoint); // Program se během čekání pozastaví; příchozí spojení Socket handler = sListener.Accept(); data řetězce = null; // Čekali jsme, až se k nám klient pokusí připojit byte bytes = new byte; int bytesRec = handler.Receive(bytes); data += Kódování.UTF8.GetString(bytes, 0, bytesRec); // Zobrazení dat na konzole Console.Write("Přijatý text: " + data + "\n\n"); // Odeslání odpovědi klientovi\ string reply = "Děkujeme za požadavek v " + data.Length.ToString() + " znaky"; byte msg = Kódování.UTF8.GetBytes(odpověď); handler.Send(msg); if (data.IndexOf(" ") > -1) ( Console.WriteLine("Server ukončil spojení s klientem."); break; ) handler.Shutdown(SocketShutdown.Both); handler.Close(); ) ) catch (exception ex) ( Console.WriteLine (ex.ToString()); ) nakonec ( Console.ReadLine(); ) ) ) )

Podívejme se na strukturu tohoto programu.

Prvním krokem je nastavení soketu na místní koncový bod. Před otevřením soketu pro naslouchání připojením pro něj musíte připravit adresu místního koncového bodu. Jedinečná adresa pro službu TCP/IP je určena kombinací IP adresy hostitele s číslem portu služby, který vytváří koncový bod pro službu.

Třída Dns poskytuje metody, které vracejí informace o síťových adresách podporovaných zařízením v lokální síť. Pokud má zařízení LAN více než jednu síťovou adresu, vrátí třída Dns informace o všech síťových adresách a aplikace musí vybrat příslušnou adresu, která bude sloužit z pole.

Vytvořme IPEndPoint pro server zkombinováním první IP adresy hostitelského počítače získané metodou Dns.Resolve() s číslem portu:

IPHostEntry ipHost = Dns.GetHostEntry("localhost"); IPAddress ipAddr = ipHost.AddressList; IPEndPoint ipEndPoint = nový IPEndPoint(ipAddr, 11000);

Zde třída IPEndPoint představuje localhost na portu 11000. Dále vytvoříme novou instanci třídy Socket stream zásuvka. Po nastavení místního koncového bodu pro naslouchání připojení můžeme vytvořit soket:

Socket sListener = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

Převod AdresaRodina určuje schémata adresování, která může instance třídy Socket použít k překladu adresy.

V parametru Typ zásuvky TCP a UDP sokety se liší. V něm můžete mimo jiné definovat následující hodnoty:

Dgram

Podporuje datagramy. Hodnota Dgram vyžaduje, aby bylo v parametru rodiny adres specifikováno Udp pro typ protokolu a síť InterNetwork.

Drsný

Podporuje přístup k základnímu transportnímu protokolu.

Proud

Podporuje streamovací zásuvky. Hodnota Stream vyžaduje, aby byl pro typ protokolu uveden Tcp.

Třetí a poslední parametr určuje typ protokolu požadovaný pro soket. V parametru Typ protokolu Můžete zadat následující nejdůležitější hodnoty - Tcp, Udp, Ip, Raw.

Dalším krokem by mělo být přiřazení soketu pomocí metody Svázat(). Když je soket otevřen konstruktorem, není mu přiřazen název, je vyhrazen pouze handle. Zavolá se metoda Bind(), která přiřadí název soketu serveru. Chcete-li umožnit klientskému soketu identifikovat soket TCP streamu, serverový program musí dát svému soketu název:

SListener.Bind(ipEndPoint);

Metoda Bind() váže soket k místnímu koncovému bodu. Metoda Bind() musí být volána před jakýmkoli pokusem o volání metod Listen() a Accept().

Nyní, když jste vytvořili soket a přiřadili k němu jméno, můžete poslouchat příchozí zprávy pomocí této metody Poslouchat(). Ve stavu naslouchání bude soket naslouchat pokusům o příchozí připojení:

SListener.Listen(10);

Parametr definuje nevyřízených, udávající maximální počet připojení čekajících ve frontě. Ve výše uvedeném kódu umožňuje hodnota parametru akumulovat až deset připojení ve frontě.

Ve stavu naslouchání musíte být připraveni souhlasit se spojením s klientem, pro který se metoda používá Akceptovat(). Tato metoda získá připojení klienta a dokončí přidružení názvu klienta a serveru. Metoda Accept() blokuje vlákno volajícího programu, dokud nedojde k připojení.

Metoda Accept() načte první požadavek na připojení z fronty nevyřízených požadavků a vytvoří jeden, který jej zpracuje. nová zásuvka. Přestože je vytvořen nový soket, původní soket nadále naslouchá a lze jej použít s vícevláknovým zpracováním k přijetí více požadavků na připojení od klientů. Žádná serverová aplikace by neměla zavřít naslouchající soket. Musí nadále fungovat vedle soketů vytvořených metodou Accept pro zpracování příchozích požadavků klientů.

While (true) ( ​​​​Console.WriteLine("Čekání na připojení na portu (0)", ipEndPoint); // Program se pozastaví při čekání na příchozí připojení Socket handler = sListener.Accept();

Jakmile klient a server navážou vzájemné spojení, lze pomocí těchto metod odesílat a přijímat zprávy Poslat() A Dostávat() zásuvka třídy.

Metoda Send() zapisuje odchozí data do připojeného soketu. Metoda Receive() čte příchozí data do streamového soketu. Při použití systému založeného na TCP musí být před provedením metod Send() a Receive() vytvořeno spojení mezi sokety. Přesný protokol mezi dvěma komunikujícími entitami musí být definován předem, aby se klientská a serverová aplikace vzájemně neblokovaly tím, že by nevěděly, kdo má jejich data odeslat jako první.

Po dokončení výměny dat mezi serverem a klientem je třeba ukončit spojení pomocí metod Vypnout() A Zavřít():

Handler.Shutdown(SocketShutdown.Both); handler.Close();

SocketShutdown je výčet obsahující tři hodnoty k zastavení: Oba- přestane posílat a přijímat data zásuvkou, Dostávat- zastaví zásuvku přijímat data a Poslat- zastaví odesílání dat zásuvkou.

Soket se uzavře voláním metody Close(), která také nastaví vlastnost Connected soketu na hodnotu false.

TCP klient

Funkce, které se používají k vytvoření klientské aplikace, jsou víceméně podobné serverové aplikaci. Stejně jako u serveru se k určení koncového bodu, vytvoření instance soketu, odesílání a přijímání dat a uzavření soketu používají stejné metody.

Jsou to nestejné komponenty informační síť. Někteří vlastní zdroj, a proto se nazývají servery, jiní k těmto zdrojům přistupují a nazývají se klienti. Podívejme se, jak se vzájemně ovlivňují a jaká je architektura klient-server.

Architektura klient-server

Architektura „klient-server“ je interakce strukturálních komponent v síti na základě komponent definovaných sítí, kde strukturální komponenty jsou server a uzly, které poskytují určité specializované funkce (služby), a také klienti, kteří tuto službu využívají. . Specifické funkce jsou obvykle rozděleny do tří skupin na základě řešení konkrétních problémů:

  • funkce zadávání dat a prezentace jsou navrženy pro interakci uživatele se systémem;
  • aplikované funkce - každá má svou vlastní sadu;
  • funkce správy zdrojů jsou navrženy pro správu systému souborů, různých databází a dalších komponent.

Například počítač bez síťového připojení představuje prezentační, aplikační a řídicí komponenty na různých úrovních. Za tyto typy úrovní se považuje operační systém, aplikační a obslužný software, různé utility. Stejně tak jsou všechny výše uvedené komponenty prezentovány na internetu. Hlavní věc je správně zajistit síťovou interakci mezi těmito komponentami.

Jak funguje architektura klient-server

Architektura klient-server se nejčastěji využívá k vytváření podnikových databází, ve kterých se informace nejen ukládají, ale také periodicky různými metodami zpracovávají. Databáze je hlavním prvkem každého podnikového informačního systému a na serveru je jádro této databáze. Na serveru tak probíhají nejsložitější operace související se zadáváním, ukládáním, zpracováním a modifikací dat. Když uživatel (klient) přistoupí k databázi (serveru), požadavek je zpracován: přímý přístup k databázi a vrácení odpovědi (výsledek zpracování). Výsledkem zpracování je síťová zpráva o úspěšnosti operace nebo chybě. Serverové počítače mohou zpracovávat současné požadavky od více klientů na stejný soubor. Taková práce po síti umožňuje urychlit práci vámi používaných aplikací.

Architektura klient-server: aplikace technologie

Tato architektura se používá pro přístup k různým zdrojům pomocí síťových technologií: databáze, poštovní servery, firewally, proxy servery. Vývoj aplikací klient-server může zlepšit bezpečnost, spolehlivost a výkon používaných aplikací a sítě jako celku. K automatizaci podnikání se nejčastěji používají klient-server aplikace.

Poslední aktualizace: 31. 10. 2015

Podívejme se, jak vytvořit vícevláknový aplikace klient-server. Ve skutečnosti se bude lišit od jednovláknového pouze v tom, že zpracování požadavku klienta bude probíhat v samostatném vlákně.

Nejprve vytvoříme projekt pro klienta. Zavolejte projekt ConsoleClient a definujte následující kód ve třídě Program:

Použití systému; pomocí System.Net.Sockets; pomocí System.Text; jmenný prostor ConsoleClient ( třída Program ( const int port = 8888; adresa const string = "127.0.0.1"; static void Main(string args) ( Console.Write("Zadejte své jméno:"); řetězec userName = Console.ReadLine() ; klient TcpClient = null string message = Console.ReadLine(); message = String.Format("(0): (1)", userName, message // převod zprávy na byte data = Encoding.Unicode.GetBytes(message) stream.Write(data, 0, data.Length) // získání dat odpovědi = nový byte // buffer pro přijatá data StringBuilder builder = new StringBuilder( bytes = stream.Read(data) ,); 0, data.Length.Append(Encoding.Unicode.GetString(data, 0, bytes)); while (stream.DataAvailable = builder.ToString( 0)", zpráva); ) ); (Výjimka ex) ( Console.WriteLine(ex.Message); ) nakonec ( client.Close(); ) ) ) )

V klientském programu uživatel nejprve zadá své jméno a poté zprávu, kterou má odeslat. Navíc bude zpráva odeslána ve formátu Jméno: zpráva.

Po odeslání zprávy klient obdrží zprávu ze serveru.

Nyní vytvoříme projekt serveru, který nazveme ConsoleServer. Nejprve přidejte do projektu serveru nová třída ClientObject, který bude představovat jedno připojení:

Použití systému; pomocí System.Net.Sockets; pomocí System.Text; jmenný prostor ConsoleServer ( public class ClientObject ( public TcpClient client; public ClientObject(TcpClient tcpClient) ( client = tcpClient; ) public void Process() ( NetworkStream stream = null; try ( stream = client.GetStream(); byte data = nový bajt); // vyrovnávací paměť pro přijatá data while (true) ( ​​​​ // získat zprávu StringBuilder builder = new StringBuilder(); int bytes = 0; do ( bytes = stream.Read(data, 0, data.Length); builder. Append(Kódování .Unicode.GetString(data, 0, bytes) while (stream.DataAvailable string message = builder.ToString( // odeslání zprávy velkými písmeny message = message.Substring (message.IndexOf.); (":") + 1).Trim().ToUpper(); data = Kódování.Unicode.GetBytes(zpráva.Write(data, 0, data.Length) ) catch(Exception); .WriteLine(ex.Message) nakonec ( if (stream != null) stream.Close(); if (client != null) client.Close(); ) ) ) ) )

V této třídě naopak nejprve obdržíme zprávu v cyklu do..while a poté ji trochu změníme (odřízneme dvojtečku a převedeme ji na velká písmena) a odešleme zpět klientovi. To znamená, že třída ClientObject obsahuje všechny akce pro práci se samostatným připojením.

V hlavní třídě projektu serveru definujeme následující kód:

Použití systému; pomocí System.Net; pomocí System.Net.Sockets; pomocí System.Threading; jmenný prostor ConsoleServer ( třída Program ( const int port = 8888; statický posluchač TcpListener; static void Main(string args) ( try ( posluchač = nový TcpListener(IPAddress.Parse("127.0.0.1"), port); listener.Start()) ; Console.WriteLine("Čekání na připojení..."); while(true) ( ​​​​TcpClient client = listener.AcceptTcpClient(); ClientObject clientObject = new ClientObject(client); // vytvořit nové vlákno pro obsluhu nového; client Thread clientThread = new Thread(new ThreadStart(clientObject.Process)); Stop(); ) ) ) )

Ihned po připojení nového klienta:

Klient TcpClient = listener.AcceptTcpClient()

Je vytvořen objekt ClientObject a je vytvořeno nové vlákno, které spouští metodu Process objektu ClientObject, kde jsou zprávy skutečně přijímány a odesílány. Server tak bude moci současně zpracovávat několik požadavků najednou.

Výsledky programu. Jeden z klientů:

Zadejte své jméno: Evgeniy Evgeniy: ahoj světe Server: HELLO WORLD Evgeniy: ahoj mír Server: BYE WORLD Evgeniy: _

Čekání na spojení... Evgeniy: ahoj světe Evgeniy: ahoj světe Tom: ahoj chat

DB fungující pomocí technologie FILE SERVER;

DB fungující pomocí technologie CLIENT-SERVER.

Souborový server


- Přístup do databáze (dotaz)
- Přenos dat při blokování přístupu jiným uživatelům
- Zpracování dat na počítači uživatele

Pro názornost uvažujme konkrétní příklady. Řekněme, že potřebujete zobrazit odeslané platební příkazy za období od 19. května do 25. května ve výši 5 000 rublů. Uživatel bude muset na svém počítači spustit klientskou aplikaci, která pracuje v databázi s platebními příkazy, a zadat potřebná výběrová kritéria. Poté bude stažen do vašeho počítače z databázového serveru a načten do RAM soubor obsahující všechny doklady tohoto typu za celé období na libovolné částky. Klientská aplikace běžící na počítači uživatele, která pracuje s databází, tyto informace zpracuje (vytřídí) a následně poskytne odpověď (na obrazovce se zobrazí seznam platebních příkazů, které splňují vaše kritéria). Poté si vyberete požadovaný platební příkaz a pokusíte se v něm upravit (změnit) jedno pole - například datum. Během editace je blokován zdroj dat, tedy celý soubor obsahující tento dokument. To znamená, že soubor buď nebude ostatním uživatelům dostupný vůbec, nebo bude dostupný pouze v režimu prohlížení. navíc tento druh k zachycení nedochází ani na úrovni záznamu, tedy jednoho dokumentu, ale uzamkne se celý soubor - tedy celá tabulka obsahující podobné dokumenty. Pouze potom plné zpracování toto pole a ukončete režim úprav tento soubor platební příkazy budou odblokovány tak, aby je uživatel nezachytil. Pokud jsou data uložena ve větších objektech, např. jeden soubor obsahuje platební příkazy pro příjem i odeslání peněžních prostředků, pak nebude k dispozici ještě více informací. V jednom dokumentu budete pracovat s jedním polem „datum“ – zbytek podnikových zaměstnanců počká, až skončíte.

Nevýhody systému FILE SERVER jsou zřejmé:

    Velmi vysoké zatížení sítě, zvýšené požadavky na šířku pásma. V praxi to pro velký počet uživatelů téměř znemožňuje pracovat s velkým množstvím dat současně.

    Zpracování dat probíhá na počítači uživatelů. To s sebou nese zvýšené požadavky na Hardware každý uživatel. Jak více uživatelů, tím více peněz budete muset utratit za vybavení jejich počítačů.

    Uzamčení dat při úpravách jedním uživatelem znemožňuje ostatním uživatelům s těmito daty pracovat.

    Bezpečnost. Abyste mohli s takovým systémem pracovat, budete muset dát každému uživateli plný přístup k celému souboru, ve kterém ho může zajímat pouze jedno pole.

    Klient-server

    Zpracování požadavku jednoho uživatele:
    - Přístup do databáze (SQL dotaz)
    - Odeslání odpovědi - výsledek zpracování


    Pokud je potřeba zpracovat informace uložené v databázi, klientská aplikace běžící na počítači uživatele, která s databází pracuje, vygeneruje dotaz v jazyce SQL (název z počátečních písmen - Structured Query Language). Databázový server přijme požadavek a zpracuje jej nezávisle. Po síti se nepřenáší žádné datové pole (soubor). Po zpracování požadavku se do počítače uživatele přenese pouze výsledek – tedy v předchozím příkladu seznam platebních příkazů, které splňují potřebná kritéria. Samotný soubor, ve kterém byla uložena data, která sloužila jako zdroj pro zpracování, zůstává odblokován pro přístup samotného serveru na žádost ostatních uživatelů.

    Vážně DBMS klient-server Existují další mechanismy, které snižují zatížení sítě a snižují požadavky na uživatelských počítačů. Jako příklad uvedeme uložené procedury – tedy celé programy pro zpracování dat uložených v databázi. V tomto případě se z uživatele na server nepřenesou ani SQL výrazy - přenese se volání funkce s parametry volání. Tím pádem, pracoviště uživatelská zkušenost je dále zjednodušena; logika programu je přenesena na server. Uživatelský prostor se stává pouze prostředkem k zobrazování informací. To vše znamená další snížení zátěže sítě a uživatelských pracovních stanic.

    Všechny výše uvedené nevýhody schématu FILE-SERVER jsou tedy v architektuře KLIENT-SERVER eliminovány:

      Datová pole nejsou přenášena po síti z databázového serveru do počítače uživatele. Požadavky na šířku pásma sítě jsou sníženy. Díky tomu může velký počet uživatelů pracovat současně s velkým množstvím dat.

      Zpracování dat probíhá na databázovém serveru, nikoli na počítači uživatele. To umožňuje použití jednodušších, a tedy levnějších počítačů na klientských stránkách.

      Data nejsou blokována (zachycována) jedním uživatelem.

      Uživateli je umožněn přístup nikoli k celému souboru, ale pouze k údajům z něj, se kterými má uživatel právo pracovat.

      Po zvážení rozdílu mezi SOUBOROVÝM SERVEREM a KLIENTSKÝM SERVEREM můžeme dokončit naši úvahu o konceptu „ukládání informací“. Je důležité zdůraznit, že provoz podnikového systému do značné míry závisí na typu použitého DBMS. Je zcela zřejmé, že pro velké podniky, s velké množství uživatelé s velkým počtem záznamů v databázi, schéma souborového serveru zcela nepřijatelné. Na druhou stranu existují rozdíly v databázích v dalších parametrech a možnostech:

        typy dat, která lze ukládat do databáze (čísla, data, text, obrázky, video, zvuk atd.);

        o technologiích organizovaných samotnou databází pro přístup k datům v databázi a úrovni ochrany informací před neoprávněným přístupem;

        na poskytnutých vývojových nástrojích a metodách, které lze použít k návrhu libovolného informačního systému založeného na této databázi;

        o poskytovaných nástrojích a metodách analýzy informací (dat), které lze aplikovat v informačním systému založeném na této databázi;

        z hlediska spolehlivosti a stability, tedy (zhruba) počtu záznamů (vyplněných polí) v databázi, který zajišťuje spolehlivou a nepřetržitou možnost přístupu, změny a analýzy informací v databázi;

        podle rychlosti – času stráveného přístupem k informacím a jejich zpracováním;

        pokud je to možné, organizujte práci na počítačích různých výrobců, tedy kompatibilitu s jinými platformami a operačními systémy;

        podle úrovně podpory (služby) poskytované vývojářem databáze nebo jejím autorizovaným prodejcem;

        podle dostupnosti dobré fondy vytváření aplikací, které používají tuto databáziúdaje atd.

        Proč se dnes nevyplácí investovat do řešení souborového serveru? Již dnes je zřejmá budoucí cesta vývoje databází. Vznikají víceúrovňové systémy klient-server, s velmi tenké klienty odstranění veškerých omezení z klientských stanic, jak z hlediska výkonu, tak platformy, operační systém. Pokud pro řešení klient-server další vývoj zdá se zcela jasné a přechod z klient-server na víceúrovňový klient-server není problematický, pak pro souborový server představuje jednoduchý přechod na klient-server obrovský problém a enormní náklady na pracovní sílu, pokud se to náhle změní aby to bylo vůbec možné.




Horní