Laden...

TCP Client: Trennen der Connect- und Sende-Funktion

Erstellt von CrocodileDundee vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.299 Views
C
CrocodileDundee Themenstarter:in
51 Beiträge seit 2018
vor 4 Jahren
TCP Client: Trennen der Connect- und Sende-Funktion

Hallo zusammen,
ich habe einen kleinen TCP-Server und einen -Client erstellt.

Der nachfolgende Quellcode zeigt den Client, dessen Form aus den folgenden
Steuerelementen besteht:

  • cmb_IPAddress - Combobox für die IP-Adressen
  • txt_Port - Textbox für den Port
  • txt_SendText - Textbox für den zu sendenden Text
  • btn_Connect - Button zum Verbinden und Senden

using System;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;


namespace TCPClientTest
{

    // ---------------------------------------------------------------------------------
    // Form
    // ---------------------------------------------------------------------------------

    public partial class MainWindow : Form
    {

        // --------------------------------------------------------------------------------
        // Declarations
        // --------------------------------------------------------------------------------

        // IP Address and Port
        private IPAddress ipAddress;
        private int port;

        // TCP Client
        private TcpClient tcpClient;
        private NetworkStream stream;


        // --------------------------------------------------------------------------------
        // Declarations
        // --------------------------------------------------------------------------------
        // Form
        // --------------------------------------------------------------------------------

        // Form: Constructor
        public MainWindow()
        {
            InitializeComponent();
        }

        // Form: Load
        private void MainWindow_Load(object sender, EventArgs e)
        {
            // Fill ComboBox of IP Address
            cmb_IPAddress.Items.Add("Loopback");
            IPHostEntry hostInfo = Dns.GetHostByName(Dns.GetHostName());            
            for(int i = 0; i < hostInfo.AddressList.Length; i++)
            {
                cmb_IPAddress.Items.Add(hostInfo.AddressList[i].ToString());
            }
            cmb_IPAddress.SelectedIndex = 0;

        }

        // Form: Closed
        private void MainWindow_FormClosed(object sender, FormClosedEventArgs e)
        {
            stream.Close();
            tcpClient.Close();
        }


        // --------------------------------------------------------------------------------
        // Controls
        // --------------------------------------------------------------------------------

        // Button: Connect
        private void btn_Connect_Click(object sender, EventArgs e)
        {
            // Detect IP Address and Port
            if (cmb_IPAddress.Text == "Loopback")
            {
                ipAddress = IPAddress.Loopback;
            }
            else
            {
                ipAddress = IPAddress.Parse(cmb_IPAddress.Text);
            }
            port = Convert.ToInt32(txt_Port.Text);


            // Send data
            tcpClient = new TcpClient();
            tcpClient.Connect(ipAddress, port);

            stream = tcpClient.GetStream();

            byte[] msgBytArr = Encoding.ASCII.GetBytes(txt_SendText.Text);
            stream.Write(msgBytArr, 0, msgBytArr.Length);
        }


    }
}

Soweit funktioniert auch alles, der TCP-Server empfängt die Daten und zeigt diese auch korrekt an.

Mein Problem ist, daß ich mit einem zusätzlichen Button die Funktionen zum Verbinden des TCP-Client und dem Senden der Daten trennen möchte, um nicht bei jedem Sendevorgang einen neuen TCP-Client erzeugen zu müßen.
Dazu habe ich einen zusätzlichen "Send"-Button eingefügt, und Code-Teile des Buttons "Connect" dorthin ausgelagert.
Der "Controls"-Bereich des neuen Quellcodes sieht somit folgendermaßen aus:



        // --------------------------------------------------------------------------------
        // Controls
        // --------------------------------------------------------------------------------

        // Button: Connect
        private void btn_Connect_Click(object sender, EventArgs e)
        {
            // Detect IP Address and Port
            if (cmb_IPAddress.Text == "Loopback")
            {
                ipAddress = IPAddress.Loopback;
            }
            else
            {
                ipAddress = IPAddress.Parse(cmb_IPAddress.Text);
            }
            port = Convert.ToInt32(txt_Port.Text);


            // Send data
            tcpClient = new TcpClient();
            tcpClient.Connect(ipAddress, port);

            stream = tcpClient.GetStream();
        }

        // Button: Send
        private void btn_Send_Click(object sender, EventArgs e)
        {
            byte[] msgBytArr = Encoding.ASCII.GetBytes(txt_SendText.Text);
            stream.Write(msgBytArr, 0, msgBytArr.Length);
        }

    }
}

Bei Ausführen bekomme ich allerdings den folgenden Effekt:

  • Der TCP-Client läßt sich mit dem Server verbinden.

  • Beim 1. Klick auf den "Send"-Button wird der Text korrekt vom Server empfangen.

  • Beim 2. Klick auf den "Send"-Button zeigt der TCP-Server keine Rekation mehr.

  • Beim 3. Klick auf den "Send"-Button wird der folgende Fehler ausgelöst:
    "In die Übertragungsverbindung können keine Daten geschrieben werden: Eine bestehende Verbindung wurde softwaregesteuert
    durch den Hostcomputer abgebrochen."

Kann mir jemand eine Tipp geben, wo der Fehler zu suchen ist?

Vielen Dank und viel Grüße
Frank

2.298 Beiträge seit 2010
vor 4 Jahren

Nach dem Fehler zu urteilen stürzt der Server entweder beim 2. Datenempfang ab oder aber bekommt schon den 2. Datenempfang nicht.

Die Meldung nach dem 3. Senden weist darauf hin, dass der Server tatsächlich die Arbeit eingestellt hat.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

16.806 Beiträge seit 2008
vor 4 Jahren

Also im Endeffekt solltest Du den gesamten Code neu schreiben.
Dass Du die gesamte Kommunikationslogik direkt in die UI wirfst ist natürlich alles andere als günstig und gut.
[Artikel] Drei-Schichten-Architektur

Kannst Dir entsprechend Events erstellen, dass Du nicht immer und immer wieder den gleichen Code schreiben musst.

Ansonsten kannst Du solche Symptome eigentlich gut debuggen
[Artikel] Debugger: Wie verwende ich den von Visual Studio?