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?
[FAQ] Warum blockiert mein GUI?
Siehe Documentation von AcceptTcpClient: diese Methode blockt (by design).
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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!
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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.
Dann trennst Du die Verbindung nicht korrekt.
Schau Dir den Inhalt der Exception an.
[Artikel] Debugger: Wie verwende ich den von Visual Studio?
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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...
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.
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).
Okay vielen Dank. Habe es jetzt soweit hinbekommen wie ich es mir vorgestellt habe.