Nous allons modifier la partie serveur de la section précédente pour recevoir en continu les messages envoyés par le client, tout en activant le multi‑threading.
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);//Création de l'adresse IP
listener = new TcpListener(ip, Convert.ToInt32(this.textBoxPort.Text));//Instanciation de l'écouteur TCP
listener.Start();
this.textBoxInfo.Text = "Serveur démarré‑" + DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
tcpClient = listener.AcceptTcpClient();//Appel bloquant, attente de connexion
this.textBoxInfo.Text = "Connexion établie‑" + 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);//Lit les octets du flux dans le tampon byteArray
//length correspond au nombre réel d'octets transmis par le client
string receiveMessage = Encoding.Unicode.GetString(byteArray, 0, length);
this.textBoxInfo.Text = "Reçu:" + receiveMessage + "-" +
DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
}
});
acceptThread.IsBackground = true;
acceptThread.Start();
}
}
}Langage du code : C# (cs)
Réalisation basée sur WinForms + TcpClient / TcpListener:
Le client envoie continuellement du texte personnalisé ; saisissez【Quitter】pour fermer la connexion et arrêter le programme
Ce code démo utilise une astuce simple pour contourner le gel de l’interface lié au multi‑threading. Cependant la bonne pratique est présentée ci‑dessous:
Control.CheckForIllegalCrossThreadCalls = false;est une méthode brutale déconseillée. Dans un projet de production, utilisezInvoke/BeginInvokepour mettre à jour les contrôles depuis un autre thread.
1. Côté serveur
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();
// Réservé à l'apprentissage, à éviter en production
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnStartServer_Click(object sender, EventArgs e)
{
// Création d’un nouveau thread pour ne pas bloquer l’interface
new Thread(() =>
{
IPAddress ip = IPAddress.Parse(textBoxIP.Text);
listener = new TcpListener(ip, Convert.ToInt32(textBoxPort.Text));
listener.Start();
AppendLog($"Serveur démarré‑{DateTime.Now.ToShortTimeString()}");
tcpClient = listener.AcceptTcpClient();
AppendLog($"Client connecté‑{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("Le client a rompu la connexion");
break;
}
string receiveMessage = Encoding.Unicode.GetString(byteArray, 0, length);
AppendLog($"Reçu:{receiveMessage} ‑{DateTime.Now.ToShortTimeString()}");
}
tcpClient.Close();
listener.Stop();
}).Start();
}
// Ajoute une ligne de journal dans la zone de texte
private void AppendLog(string msg)
{
textBoxInfo.Text = msg + "\r\n" + textBoxInfo.Text;
}
}
}Langage du code : C# (cs)
2. Code côté client
Implémente une saisie continue ; taper «Quitter» met fin aux échanges
Contrôles à prévoir sur le formulaire client:
textBoxServerIp:Adresse IP du serveurtextBoxPort:Numéro de porttextBoxSend:Champ de saisie des messages à envoyerbtnConnect:Bouton de connexionbtnSend:Bouton d’envoi
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;
}
// Connexion au serveur
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("Connexion établie, vous pouvez envoyer vos messages !");
}
catch (Exception ex)
{
MessageBox.Show("Échec de la connexion:" + ex.Message);
}
}
// Logique principale d’envoi des messages
private void btnSend_Click(object sender, EventArgs e)
{
if (!isConnected)
{
MessageBox.Show("Veuillez d’abord vous connecter au serveur !");
return;
}
string content = textBoxSend.Text.Trim();
if (string.IsNullOrEmpty(content))
return;
// Détection de la commande de sortie
if (content == "Quitter")
{
byte[] exitData = Encoding.Unicode.GetBytes(content);
stream.Write(exitData, 0, exitData.Length);
// Libération des ressources
stream.Close();
client.Close();
isConnected = false;
MessageBox.Show("Connexion terminée");
return;
}
// Envoi d’un message personnalisé
byte[] data = Encoding.Unicode.GetBytes(content);
stream.Write(data, 0, data.Length);
textBoxSend.Clear();
}
}
}Langage du code : 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("Saisissez votre message:");
string msg = Console.ReadLine();
byte[] buf = Encoding.Unicode.GetBytes(msg);
stream.Write(buf,0,buf.Length);
if (msg == "Quitter")
{
stream.Close();
client.Close();
break;
}
}
}Langage du code : JavaScript (javascript)
Si vous le souhaitez, je peux réécrire l’ensemble du code selon le schéma async/await entièrement asynchrone, pour supprimer complètement les threads secondaires ainsi que la mauvaise pratique de désactiver la vérification des appels inter‑threads.
Envoi continu depuis le client