Laden...

[erledigt]TCP Chat GUI hängt sich auf bis Client verbunden ist

Erstellt von Jan_kie vor 5 Jahren Letzter Beitrag vor 5 Jahren 2.534 Views
J
Jan_kie Themenstarter:in
11 Beiträge seit 2018
vor 5 Jahren
[erledigt]TCP Chat GUI hängt sich auf bis Client verbunden ist

Hallo,

ich soll für die Arbeit eine Art Chatanwendung programmieren, welche in beide Richtungen funktioniert. Da ich kompletter Anfänger bin was C# und besonders Netzwerktechnologien angeht, habe ich einige Probleme bei denen ich nicht weiter komme.

Wenn ich den Server starte, hängt meine Server-GUI solange, bis sich der Client verbunden hat.
Im Debugger bleibt er dort bei:

client = listener.AcceptTcpClient();

stehen.
Auch die Zeile:

textBox_Input.Text += "Verbindung hergestellt." + Environment.NewLine;

wird erst ausgeführt, sobald sich der Client mit dem Server verbunden hat.

Code vom Server:

        public void DoWork()
        {
            byte[] bytes = new byte[1024];
            while (true)
            {
                int bytesRead = ns.Read(bytes, 0, bytes.Length);
                this.SetText(Encoding.ASCII.GetString(bytes, 0, bytesRead));
            }
        }

        private void SetText(string text)
        {
            if (this.textBox_Input.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox_Input.Text = this.textBox_Input.Text + text;
            }
        }

        private void button_Starten_Click(object sender, EventArgs e)
        {
            IPAddress hostname = IPAddress.Parse(textBox_Hostname.Text);
            int portNum = Convert.ToInt32(textBox_Port.Text);
            listener = new TcpListener(hostname, portNum);
            listener.Start();
            client = listener.AcceptTcpClient();
            ns = client.GetStream();
            t = new Thread(DoWork);
            t.Start();
            textBox_Input.Text += "Verbindung hergestellt." + Environment.NewLine;
        }

Code vom Client:

        public void DoWork()
        {
            byte[] bytes = new byte[1024];
            while (true)
            {
                int bytesRead = ns.Read(bytes, 0, bytes.Length);
                this.SetText(Encoding.ASCII.GetString(bytes, 0, bytesRead));
            }
        }

        private void SetText(string text)
        {
            if (this.textBox_Input.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox_Input.Text = this.textBox_Input.Text + text;
            }
        }

        private void button_Connect_Click(object sender, EventArgs e)
        {
            string hostName = textBox_Hostname.Text;
            int portNum = Convert.ToInt32(textBox_Port.Text);
            client = new TcpClient(hostName, portNum);
            ns = client.GetStream();
            t = new Thread(DoWork);
            t.Start();
            textBox_Input.Text += "Verbindung hergestellt." + Environment.NewLine;
        }


Ich hoffe ihr könnt mir weiterhelfen, auch wenn ich eigentlich erstmal an den Grundkenntnissen arbeiten sollte.

Mit freundlichen Grüßen

Jan_kie

#edit: habe herausgefunden dass es wirklich an

client = listener.AcceptTcpClient();

liegt und ich mit Pending arbeiten muss, hat da jemand ein paar Infos zu?

16.807 Beiträge seit 2008
vor 5 Jahren

[FAQ] Warum blockiert mein GUI?

Siehe Documentation von AcceptTcpClient: diese Methode blockt (by design).

J
Jan_kie Themenstarter:in
11 Beiträge seit 2018
vor 5 Jahren

Also müsste ich diese Methode in einem extra Thread laufen lassen?

16.807 Beiträge seit 2008
vor 5 Jahren

Es gibt auch eine asynchrone Implementierung; Du musst einfach mal in die (sehr ausführliche!) Dokumentation schauen oder einfach mal 2 Minuten in die Forensuche investieren, dann findest Du schon Beispiele und kommst schneller voran als mit raten 😉
Das geht auch als Einsteiger dann leichter 😉

> Klasse soll ein Formular verstecken und anzeigen (ja hier ist wirklich ein Beispiel drin!)

PS: in .NET immer versuchen mit Tasks zu arbeiten; nicht direkt mit der Thread-Klasse!

J
Jan_kie Themenstarter:in
11 Beiträge seit 2018
vor 5 Jahren

Habe es jetzt hinbekommen indem ich


        private void AcceptTCP()
        {
            client = listener.AcceptTcpClient();
            ns = client.GetStream();
            t = new Thread(DoWork);
            t.IsBackground = true;
            t.Start();
        }

in eine neue Funktion ausgelagert habe und diese mit

            Task task = new Task(() => AcceptTCP());

aufrufe.

Weiß nicht genau ob das die Antwort war die du meintest aber es funktioniert. Kann man das denn so machen oder ist das "unsauber"?

Habe jetzt allerdings einen neuen Fehler, sobald der Client die bestehende Verbindung trennt.

edit: Fehlermeldung die nun kommt:

Fehlermeldung:
Ein Ausnahmefehler des Typs "System.IO.IOException" ist in System.dll aufgetreten.

Von der Übertragungsverbindung können keine Daten gelesen werden: Eine vorhandene Verbindung wurde vom Remotehost geschlossen.

edit2: ich glaube der neue Fehler hat etwas mit dem NetworkStream zu tun, da er in

int bytesRead = ns.Read(bytes, 0, bytes.Length);

ausgelöst wird.

16.807 Beiträge seit 2008
vor 5 Jahren

Dann trennst Du die Verbindung nicht korrekt.
Schau Dir den Inhalt der Exception an.
[Artikel] Debugger: Wie verwende ich den von Visual Studio?

J
Jan_kie Themenstarter:in
11 Beiträge seit 2018
vor 5 Jahren

Okay, weiß jetzt woran es gelegen hat. Mein FormClosing-Event war nicht an die Form angebunden, also haben die Sachen nicht beim schließen ausgelöst.

#edit: Allerdings kommt jetzt ein anderer Fehler

"Ein Blockierungsvorgang wurde durch einen Aufruf von WSACancelBlockingCall unterbrochen."

Wenn ich die Client Form schließen will und der Client mit dem Server verbunden ist, dabei dache ich, dass ich jetzt alles richtig geschlossen habe.

#edit2: Wenn ich nichts schließe, also

        private void frmClient_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (ns != null)
            {
                ns.Close();
                ns.Dispose();
            }

            if (client != null)
            {
                client.Close();
            }

            if (Work != null)
            {
                Work.Dispose();
            }
        }

auskommentiere, dann kommt die oben genannte Exception nicht.

Hoffe mir kann einer erklären wieso das so ist...

463 Beiträge seit 2009
vor 5 Jahren

Okay, weiß jetzt woran es gelegen hat. Mein FormClosing-Event war nicht an die Form angebunden, also haben die Sachen nicht beim schließen ausgelöst..

Dies hättest du viel schneller herausfinden können, wenn du den Debugger [Artikel] Debugger: Wie verwende ich den von Visual Studio? benutzt hättest.

4.931 Beiträge seit 2008
vor 5 Jahren

Hallo Jan_kie,

zu deinem letzten Fehler: packe den gesamten Thread-Code in einen try..catch-Block und fange diese Exception, s.a. Socket aus anderem Thread schliessen (ist zwar VB.NET Code, aber einfach auf C# übertragbar).

J
Jan_kie Themenstarter:in
11 Beiträge seit 2018
vor 5 Jahren

Okay vielen Dank. Habe es jetzt soweit hinbekommen wie ich es mir vorgestellt habe.