TCP/IP na przykładzie .NET
Transkrypt
TCP/IP na przykładzie .NET
TCP/IP na przykładzie .NET Pierwszy podstawowy program Uruchamiamy Visual Studio Zakładamy nowy projekt (ctrl+shift+n) Pierwszy podstawowy program Z zakładki „tools” wybieramy odpowiednie kontrolki i układamy na formatce Pierwszy podstawowy program We właściwościach zmieniamy następujące parametry •Minimum size: 300;300 •Name: textBoxAdres •Name: textBoxPort •Name: buttonPolacz •Name: buttonSerwuj •Name: richTextBoxOdbior •Name: textBoxKomunikat •Name: buttonWyslij •Anchor: Top, Left, Right •Anchor: Top •Anchor: Top, Bottom, Left, Right •Anchor: Bottom, Left, Right Pierwszy podstawowy program Używamy dodatkowej przestrzeni nazw: using System.Net.Sockets; using System.Net; W klasie Form1 dodajemy zmienne private TcpListener tcpLsn; private Encoding ASCII = Encoding.ASCII; //kodowanie Socket s; Pierwszy podstawowy program Dodajemy obsługę guzika „Serwuj” private void buttonSerwuj_Click(object sender, EventArgs e) { tcpLsn = new TcpListener(IPAddress.Parse(textBoxAdres.Text), int.Parse(textBoxPort.Text)); //zainicjiuj listenera na podanym porcie i adresie tcpLsn.Start(); Socket sckt = tcpLsn.AcceptSocket(); //funkcja blokująca do czasu nadejścia połączenia Byte[] odebraneBajty = new Byte[100]; int ret = sckt.Receive(odebraneBajty, odebraneBajty.Length, 0); string tmp = null; tmp = System.Text.Encoding.ASCII.GetString(odebraneBajty); if (tmp.Length > 0) { richTextBoxOdbior.AppendText(tmp); } tcpLsn.Stop(); } Pierwszy podstawowy program Dodajemy obsługę guzika „Połącz” oraz „Wyślij” private void buttonPolacz_Click(object sender, EventArgs e) { s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress hostadd = IPAddress.Parse(textBoxAdres.Text); int port = Int32.Parse(textBoxPort.Text); IPEndPoint EPhost = new IPEndPoint(hostadd, port); s.Connect(EPhost); } private void buttonWyslij_Click(object sender, EventArgs e) { string str = textBoxKomunikat.Text; Byte[] byteData = ASCII.GetBytes(str.ToCharArray()); s.Send(byteData, byteData.Length, 0); } Pierwszy podstawowy program Pierwsza działająca wersja ale ma poważne wady: Usługa zadziała tylko raz (przydałaby się pętla) Jest kilka blokujących funkcji przez co tracimy kontrolę w głównej formatce (przydałby się osobny wątek) Brak obsługi błędów Brak możliwości wielokrotnego podłączania się i odłączania Brak uodpornienia interfejsu na głupie zachowania 2 wersja programu część powyższych ma wyeliminowane Drugi program We właściwościach zmieniamy dodatkowo następujące parametry: •Text: 127.0.01 •Text: 2222 •ReadOnly: true •Enabled: false Drugi program public delegate void DodajKolorowyTekst(RichTextBox RichTextBox, string Text, Color kolor); private void DodajKolorowyTekstFn(RichTextBox rtb, string tekst, Color kolor) { var StartIndex = rtb.TextLength; rtb.AppendText(tekst); var EndIndex = rtb.TextLength; rtb.Select(StartIndex, EndIndex - StartIndex); rtb.SelectionColor = kolor; } private void AppendColoredText(RichTextBox RTB, string Text, Color kolor) { if (RTB.InvokeRequired) { RTB.Invoke(new DodajKolorowyTekst(DodajKolorowyTekstFn), RTB, Text, kolor); } else { DodajKolorowyTekstFn(RTB, Text, kolor); } } private Encoding ASCII = Encoding.ASCII; //kodowanie private TcpListener tcpLsn; Socket s; Thread tcpThd; Drugi program private void buttonSerwuj_Click(object sender, EventArgs e) { if (buttonSerwuj.Text == "Stop") { try { tcpThd.Abort(); tcpLsn.Stop(); buttonSerwuj.Text = "Serwuj"; buttonPolacz.Enabled = true; textBoxAdres.Enabled = true; textBoxPort.Enabled = true; } catch (Exception ex) { AppendColoredText(richTextBoxOdbior, "Bład odłączenia: \n", Color.Red); AppendColoredText(richTextBoxOdbior, ex.Message + "\n", Color.Red); } } Drugi program else { try { //zainicjiuj listenera na podanym porcie i adresie tcpLsn = new TcpListener(IPAddress.Parse(textBoxAdres.Text),int.Parse(textBoxPort.Text)); tcpLsn.Start(); AppendColoredText(richTextBoxOdbior, "Słucham na: ", Color.Red); AppendColoredText(richTextBoxOdbior, tcpLsn.LocalEndpoint.ToString() + "\n", Color.Blue); //przygotowanie wątku czekającego na połączenia tcpThd = new Thread(new ThreadStart(WaitingForClient)); tcpThd.Start(); //wystartowanie wątku czekającego na połączenia buttonSerwuj.Text = "Stop"; //zmiana nazwy buttonPolacz.Enabled = false; //zmiany stanów textBoxAdres.Enabled = false; textBoxPort.Enabled = false; } catch (Exception ex) { AppendColoredText(richTextBoxOdbior, "Bład połączenia: \n", Color.Red); AppendColoredText(richTextBoxOdbior, ex.Message + "\n", Color.Red); } } } Drugi program public void WaitingForClient() { while (true) { try { Socket sckt = tcpLsn.AcceptSocket(); Byte[] odebraneBajty = new Byte[textBoxKomunikat.MaxLength]; AppendColoredText(richTextBoxOdbior, "Podłączony klient z: ", Color.Red); AppendColoredText(richTextBoxOdbior, sckt.RemoteEndPoint.ToString() + "\n", Color.Blue); while (sckt.Connected) { try { int ret = sckt.Receive(odebraneBajty, odebraneBajty.Length, 0); if (ret > 0) { string tmp = null; odebraneBajty[ret] = 0; tmp = System.Text.Encoding.ASCII.GetString(odebraneBajty); if (tmp.Length > 0) { AppendColoredText(richTextBoxOdbior, tmp, Color.Black); AppendColoredText(richTextBoxOdbior, "\n", Color.Black); } } Drugi program else { AppendColoredText(richTextBoxOdbior, "Błąd odbioru\n", Color.Red); break; } } catch (Exception ex) { if (!sckt.Connected) { AppendColoredText(richTextBoxOdbior, "Połaczenie zerwane\n", Color.Red); AppendColoredText(richTextBoxOdbior, ex.Message + "\n", Color.Red); break; } } } } catch (Exception ex) { MessageBox.Show("Koniec: " + ex.Message); } } } Drugi program private void buttonPolacz_Click(object sender, EventArgs e) { if (buttonPolacz.Text == "Odłącz") { try { s.Disconnect(false); textBoxKomunikat.Enabled = false; buttonWyslij.Enabled = false; buttonSerwuj.Enabled = true; textBoxAdres.Enabled = true; textBoxPort.Enabled = true; buttonPolacz.Text = "Połacz"; AppendColoredText(richTextBoxOdbior, "Odłączono \n", Color.Red); } catch (Exception ex) { AppendColoredText(richTextBoxOdbior, "Błąd odłaczenia: \n", Color.Red); AppendColoredText(richTextBoxOdbior, ex.Message + "\n", Color.Red); } } Drugi program else { try { s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress hostadd = IPAddress.Parse(textBoxAdres.Text); int port = Int32.Parse(textBoxPort.Text); IPEndPoint EPhost = new IPEndPoint(hostadd, port); s.Connect(EPhost); if (s.Connected) { textBoxKomunikat.Enabled = true; buttonWyslij.Enabled = true; buttonSerwuj.Enabled = false; textBoxAdres.Enabled = false; textBoxPort.Enabled = false; buttonPolacz.Text = "Odłącz"; AppendColoredText(richTextBoxOdbior, "Podłączono \n", Color.Red); } } catch (Exception ex) { AppendColoredText(richTextBoxOdbior, "Błąd podłaczenia: \n", Color.Red); AppendColoredText(richTextBoxOdbior, ex.Message + "\n", Color.Red); } } } Drugi program private void buttonWyslij_Click(object sender, EventArgs e) { if (s != null && s.Connected) //jeżeli jesteśmy podłączeni to wysyłamy { string str = textBoxKomunikat.Text; Byte[] byteData = ASCII.GetBytes(str.ToCharArray()); s.Send(byteData, byteData.Length, 0); } } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { if (tcpThd != null) tcpThd.Abort(); if (tcpLsn != null) tcpLsn.Stop(); } Trzecia wersja programu Wprowadzono następujące modyfikacje: Obsługa wielu klientów jednocześnie (serwer wielowątkowy) Wydzielenie obsługi połączeń do osobnej klasy Dzięki serializacji i deserializacji przekazywanie całych obiektów Informowanie za pomocą zdarzeń.