Im Folgenden passen wir den serverseitigen Code aus dem vorherigen Abschnitt an. Der Server soll Nachrichten des Clients dauerhaft empfangen, zudem aktivieren wir die Multithreading‑Unterstützung.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace TcpServerDemo
{
public partial class Form1 : Form
{
private TcpListener listener;
private TcpClient tcpClient;
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnStartServer_Click(object sender, EventArgs e)
{
Thread acceptThread = new Thread(() =>
{
IPAddress ip = IPAddress.Parse(this.textBoxIP.Text);//IP‑Adresse erstellen
listener = new TcpListener(ip, Convert.ToInt32(this.textBoxPort.Text));//TCP‑Listener‑Objekt erzeugen
listener.Start();
this.textBoxInfo.Text = "Server gestartet‑" + DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
tcpClient = listener.AcceptTcpClient();//blockierender Aufruf, wartet auf Verbindung
this.textBoxInfo.Text = "Verbindung aufgebaut‑" + DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
NetworkStream stream = tcpClient.GetStream();
byte[] byteArray = new byte[1024];
while (true)
{
int length = stream.Read(byteArray, 0, 1024);//liest Bytes aus dem Stream in byteArray‑Puffer
//length gibt die tatsächliche Byte‑Anzahl der Client‑Nachricht an
string receiveMessage = Encoding.Unicode.GetString(byteArray, 0, length);
this.textBoxInfo.Text = "Empfangen:" + receiveMessage + "-" +
DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
}
});
acceptThread.IsBackground = true;
acceptThread.Start();
}
}
}Code-Sprache: C# (cs)
Realisierung mit WinForms + TcpClient / TcpListener:
Der Client sendet beliebige Texte fortlaufend an den Server. Gib 【Beenden】ein, um die Verbindung zu trennen und das Programm zu schließen
Dieses Demo umgeht Multithreading‑UI‑Hänger auf einfache Weise, die korrekte Vorgehensweise sieht aber so aus:
Control.CheckForIllegalCrossThreadCalls = false;ist eine nicht empfohlene grobe Notlösung. Für Produktivcode nutzeInvoke/BeginInvokeum Steuerelemente aus fremden Threads zu aktualisieren.
1. Serverseite
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
namespace TcpServerDemo
{
public partial class Form1 : Form
{
private TcpListener listener;
private TcpClient tcpClient;
public Form1()
{
InitializeComponent();
// Nicht für Produktivprojekte, nur zu Lernzwecken
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnStartServer_Click(object sender, EventArgs e)
{
// Neuer Thread um UI‑Blockaden zu vermeiden
new Thread(() =>
{
IPAddress ip = IPAddress.Parse(textBoxIP.Text);
listener = new TcpListener(ip, Convert.ToInt32(textBoxPort.Text));
listener.Start();
AppendLog($"Server gestartet‑{DateTime.Now.ToShortTimeString()}");
tcpClient = listener.AcceptTcpClient();
AppendLog($"Client verbunden‑{DateTime.Now.ToShortTimeString()}");
NetworkStream stream = tcpClient.GetStream();
byte[] byteArray = new byte[1024];
while (true)
{
int length = stream.Read(byteArray, 0, 1024);
if (length <= 0)
{
AppendLog("Client hat Verbindung getrennt");
break;
}
string receiveMessage = Encoding.Unicode.GetString(byteArray, 0, length);
AppendLog($"Empfangen:{receiveMessage} ‑{DateTime.Now.ToShortTimeString()}");
}
tcpClient.Close();
listener.Stop();
}).Start();
}
// Log‑Zeile an Textbox anhängen
private void AppendLog(string msg)
{
textBoxInfo.Text = msg + "\r\n" + textBoxInfo.Text;
}
}
}Code-Sprache: C# (cs)
2. Client‑Code
Funktion: fortlaufende Eingabe, Eingabe von „Beenden“ beendet die Kommunikation
Folgende Steuerelemente für das Client‑Formular vorsehen:
textBoxServerIp:IP‑Adresse des ServerstextBoxPort:PortnummertextBoxSend:Eingabefeld für zu versendende NachrichtenbtnConnect:Verbindungs‑ButtonbtnSend:Sende‑Button
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace TcpClientDemo
{
public partial class ClientForm : Form
{
private TcpClient client;
private NetworkStream stream;
private bool isConnected = false;
public ClientForm()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
// Verbindung zum Server aufbauen
private void btnConnect_Click(object sender, EventArgs e)
{
try
{
client = new TcpClient();
client.Connect(textBoxServerIp.Text, Convert.ToInt32(textBoxPort.Text));
stream = client.GetStream();
isConnected = true;
MessageBox.Show("Verbindung hergestellt, du kannst jetzt Nachrichten senden!");
}
catch (Exception ex)
{
MessageBox.Show("Verbindungsfehler:" + ex.Message);
}
}
// Kernlogik zum Senden von Nachrichten
private void btnSend_Click(object sender, EventArgs e)
{
if (!isConnected)
{
MessageBox.Show("Zuerst mit dem Server verbinden!");
return;
}
string content = textBoxSend.Text.Trim();
if (string.IsNullOrEmpty(content))
return;
// Prüfen ob Beenden‑Befehl eingegeben wurde
if (content == "Beenden")
{
byte[] exitData = Encoding.Unicode.GetBytes(content);
stream.Write(exitData, 0, exitData.Length);
// Ressourcen freigeben
stream.Close();
client.Close();
isConnected = false;
MessageBox.Show("Verbindung getrennt");
return;
}
// Normalen Inhalt versenden
byte[] data = Encoding.Unicode.GetBytes(content);
stream.Write(data, 0, data.Length);
textBoxSend.Clear();
}
}
}Code-Sprache: C# (cs)
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 8899);
NetworkStream stream = client.GetStream();
while (true)
{
Console.Write("Gib den zu sendenden Inhalt ein:");
string msg = Console.ReadLine();
byte[] buf = Encoding.Unicode.GetBytes(msg);
stream.Write(buf,0,buf.Length);
if (msg == "Beenden")
{
stream.Close();
client.Close();
break;
}
}
}Code-Sprache: JavaScript (javascript)
Bei Bedarf kann ich den gesamten Quellcode auf rein asynchrone async/await‑Syntax umschreiben. Dadurch verzichten wir komplett auf Hilfsthreads und die unsaubere Deaktivierung des Cross‑Thread‑Prüfers.
Fortlaufendes Senden auf Client‑Seite