Utilisation des sockets en C#
Date de publication : 10/10/2004
Par
Stéphane Eyskens (Autres articles)
Dans cet article nous allons aborder les sockets. Les sockets sont des points de communication au sein d'un réseau
ou d'une même machine permettant à des processus d'échanger des informations. Les chats sont généralement basés sur les sockets.
Nous vous proposons donc d'étudier le chat développé pour ce tutoriel.
1. Introduction
1.1. Les principales méthodes de la classe Sockets que nous avons utilisées pour réaliser le chat
1.2. Architecture de notre chat
1.3. Copies d'écran
1.4. Le serveur
1.5. Le client
2. Téléchargement
1. Introduction
Pour les besoins de ce tutoriel, nous avons développé une application de chat se basant sur les sockets. Cette application
est composée d'un serveur et d'un client. Nous utiliserons la classe System.Net.Sockets. Il eut été possible d'utiliser
aussi les classes TcpClient et TcpServer. Nous travaillerons en mode synchrone multi-thread et avec des connexions
en mode "connecté". Le mode connecté signifie que lorsque le client a établi une connexion avec le serveur, celle-ci reste ouverte
jusqu'à ce que l'un des process décide de la fermer ou qu'un problème réseau survient. Je fais cette précision car il est possible
de travailler en mode "déconnecté", c'est à dire qu'un client se connecte sur un serveur, celui-ci traite l'info et renvoie un
"ack" (acknowledgement) au client qui dès réception de cet ack ferme la connexion.
Le chat comprend les fonctionnalités suivantes:
- Pas de limitation au niveau du nombre de clients pouvant se connecter simultanément
- Notification des connectés/déconnectés
- Notification des messages reçus par un clignotement de fenêtre si celle-ci est réduite
- Formattage des messages en RTF à la volée. Nous aurions pu nous contenter du mode texte qui est beaucoup plus facile à gérer. Car outre sa relative complexité,
le mode RTF est moins performant et est sensible à certains caractères spéciaux comme les accolades par exemple.
1.1. Les principales méthodes de la classe Sockets que nous avons utilisées pour réaliser le chat
| Méthode | Description |
| Socket.Bind | Lie la socket à un point de communication, renvoie une erreur si le port spécifié par le point de communication est déjà utilisé par un autre processus |
| Socket.Listen | Place en file d'attente (queue) toutes les connexions entrantes |
| Socket.Accept | Lit la file d'attente et accepte les connexions entrantes. Accept est bloquant, l'exécution du code est bloquée jusqu'à ce qu'accept détecte une connexion entrante dans la file d'attente |
| Socket.Select | Permet entre-autre, de vérifier si une socket connectée tente d'écrire quelque chose. En passant un tableau de connexion en paramètre à select, après l'exécution de select, le tableau ne contient plus que les sockets ayant des données prêtes à être lues |
| Socket.Poll | Permet, un peu comme select, de détecter si une socket est prête à être lue ou écrite. A l'inverse de select, elle permet aussi de détecter si une connexion est terminée (voir commentaire dans le code). |
| Socket.Receive | Permet de réceptionner les données qui ont été écrites sur la socket |
| Socket.Send | Permet d'écrire des données sur une socket |
| Socket.Connect | Permet de se connecter à une socket |
1.2. Architecture de notre chat
Comme vous pouvez le constater, la communication entre le serveur et le(s) client(s) est basée sur le protocole TCP/IP. Cette communication
peut avoir lieu au sein d'un réseau ou d'une même machine. Les connexions établies restent donc en mode "connecté" jusqu'à ce que l'un
des processus décide de les fermer.
Le code du serveur est "divisé" en quatre parties:
- Le thread principal: c'est lui qui crée la socket d'écoute sur le serveur, ensuite, dans une boucle infinie, il attend de nouvelles connexions entrantes (socket.accept). Il démarre préalablement le thread d'écoute et le thread
vérifiant que les connexions clientes sont toujours active. Le 2ème et 3ème thread sont démarrés avant même qu'une connexion cliente ait eu lieu. Etant donné qu'ils ne consomment quasiment aucune
ressource, ce n'est pas préjudiciable. Il est en fait plus facile de les démarrer avant, car dans ce cas, on a pas à vérifier s'ils sont déjà démarrés ou pas lorsqu'on les démarre. J'aurais pu ne les démarrer que lorsqu'au moins une connexion
cliente soit effectuée mais j'ai opté pour la facilité, d'autant que l'impact sur les performances est nul
- Le 2ème thread se charge de lire en permanence les données écrites par les clients. Il démarre le thread d'écriture lorsqu'il reçoit des données
- Le 3ème thread se charge de vérifier que les connexions clientes sont toujours active
- Le 4ème thread est démarré lorsque le 2ème thread a lu des données sur une socket
Le code du client est lui, un peu plus simple
- Le thread principal se charge de créer et de connecter la socket cliente au serveur et gère les évènements liés aux contrôles winform
- Le 2ème thread se charge de lire les données entrantes que le serveur envoie au client
- Le 3ème thread est démarré sur demande et se charge de faire clignoter la fenêtre
Pour rappel, un thread est un ensemble d'instructions s'exécutant au sein d'un même processus en parralèle aux autres thread
démarrés dans ce processus. Ceci permet donc d'avoir plusieurs "entités" de code plus ou moins autonomes. Cela permet donc
d'accroître les performances. Pour illustrer ceci, prenons simplement le serveur, s'il n'avait pas plusieurs threads, à chaque fois
qu'il accepte une connexion, il devrait lire les données envoyées par celle-ci et renvoyer ces données aux autres clients. Pendant ce temps,
il ne pourrait donc plus se remettre en attente de connexion. En mode multi-thread, dès qu'il reçoit une connexion, il se remet immédiatement en
attente.
1.3. Copies d'écran
L'écran de connexion. Entrez successivement le nom du serveur sur lequel l'exécutable "serveur.exe" tourne suivi du nom du pseudo. Vous pouvez
enregistrer les paramètres de connexion qui seront stockés dans un fichier pour ne plus devoir réentrer ultérieurement ces paramètres.
L'option "Faire clignoter la fenêtre" permet d'activer le clignotement de la fenêtre lorsque celle-ci n'est pas active et que vous recevez un message.
L'écran du chat. C'est ici que vous entrerez vos propres messages et que vous visualiserez les messages des autres utilisateurs. Les notifications de connexion/déconnexion
d'autres utilisateurs seront affichées dans le RichTextBox principal. Le RichTextBox dans lequel vous saisissez vos messages est limité à 4ko.
1.4. Le serveur
Veuillez m'excuser pour l'indentation peu lisible du code. Ceci est principalement dû au fait que j'essaye
que le code tienne dans une résolution 1024*768.
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Threading;
using System.IO;
namespace DefaultNamespace
{
public class Server:forwardToAll
{
ArrayList readList=new ArrayList();
string msgString=null;
string msgDisconnected=null;
byte[] msg
public bool useLogging=false;
public bool readLock=false
private string rtfMsgEncStart="\pard\cf1\b0\f1 "
private string rtfMsgContent="\cf2 "
private string rtfConnMsgStart="\pard\qc\b\f0\fs20 ";
public void Start()
{
IPHostEntry ipHostEntry = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostEntry.AddressList[0];
Console.WriteLine("IP="+ipAddress.ToString());
Socket CurrentClient=null;
Socket ServerSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
try
{
ServerSocket.Bind(new IPEndPoint(ipAddress, 8000));
ServerSocket.Listen(10);
Thread getReadClients = new Thread(new ThreadStart(getRead));
getReadClients.Start();
Thread pingPongThread = new Thread(new ThreadStart(CheckIfStillConnected));
pingPongThread.Start();
while(true){
Console.WriteLine("Attente d'une nouvelle connexion...");
CurrentClient=ServerSocket.Accept();
Console.WriteLine("Nouveau client:"+CurrentClient.GetHashCode());
acceptList.Add(CurrentClient);
}
}
catch(SocketException E)
{
Console.WriteLine(E.Message);
}
}
private void Logging(string message)
{
using (StreamWriter sw = File.AppendText("chatServer.log"))
{
sw.WriteLine(DateTime.Now+": "+message);
}
}
private void writeToAll()
{
base.sendMsg(msg);
}
private void infoToAll()
{
base.sendMsg(msgDisconnected);
}
private void CheckIfStillConnected()
{
/* Etant donné que la propriété .Connected d'une socket n'est pas
* mise à jour lors de la déconnexion d'un client sans que l'on ait
* prélablement essayé de lire ou d'écrire sur cette socket, cette méthode
* parvient à déterminer si une socket cliente s'est déconnectée grce à la méthode
* poll. On effectue un poll en lecture sur la socket, si le poll retourne vrai et que
* le nombre de bytes disponible est 0, il s'agit d'une connexion terminée*/
while(true)
{
for(int i=0;i<acceptList.Count;i++)
{
if(((Socket)acceptList[i]).Poll(10,SelectMode.SelectRead) && ((Socket)acceptList[i]).Available==0)
{
if(!readLock)
{
Console.WriteLine("Client "+((Socket)acceptList[i]).GetHashCode()+" déconnecté");
removeNick(((Socket)acceptList[i]));
((Socket)acceptList[i]).Close();
acceptList.Remove(((Socket)acceptList[i]));
i--;
}
}
}
Thread.Sleep(5);
}
}
private bool checkNick(string nick,Socket Resource)
{
if(MatchList.ContainsValue(nick))
{
((Socket)acceptList[acceptList.IndexOf(Resource)]).Shutdown(SocketShutdown.Both);
((Socket)acceptList[acceptList.IndexOf(Resource)]).Close();
acceptList.Remove(Resource);
Console.WriteLine("Pseudo déjà pris");
return false;
}
else
{
MatchList.Add(Resource,nick);
getConnected();
}
return true;
}
private void removeNick(Socket Resource)
{
Console.Write("DECONNEXION DE:"+MatchList[Resource]);
msgDisconnected=rtfConnMsgStart+((string)MatchList[Resource]).Trim()+" vient de se déconnecter!\par";
Thread DiscInfoToAll=new Thread(new ThreadStart(infoToAll));
DiscInfoToAll.Start();
DiscInfoToAll.Join();
MatchList.Remove(Resource);
}
private void getRead()
{
while(true)
{
readList.Clear();
for(int i=0;i<acceptList.Count;i++){
readList.Add((Socket)acceptList[i]);
}
if(readList.Count>0)
{
Socket.Select(readList, null, null, 1000);
for(int i=0;i<readList.Count;i++)
{
if(((Socket)readList[i]).Available>0)
{
readLock=true;
int paquetsReceived=0;
long sequence=0;
string Nick=null;
string formattedMsg=null;
while(((Socket)readList[i]).Available>0)
{
msg = new byte[((Socket)readList[i]).Available];
((Socket)readList[i]).Receive(msg,msg.Length,SocketFlags.None);
msgString=System.Text.Encoding.UTF8.GetString(msg);
if(paquetsReceived==0)
{
string seq=msgString.Substring(0,6);
try
{
sequence=Convert.ToInt64(seq);
Nick=msgString.Substring(6,15);
formattedMsg=rtfMsgEncStart+Nick.Trim()+" a écrit:"+rtfMsgContent+
msgString.Substring(20,(msgString.Length-20))+"\par";
}
catch
{
Console.Write("Message non conforme");
acceptList.Remove(((Socket)readList[i]));
break;
}
}
else
{
formattedMsg=rtfMsgContent+msgString+"\par";
}
msg=System.Text.Encoding.UTF8.GetBytes(formattedMsg);
if(sequence==1){
if(!checkNick(Nick,((Socket)readList[i])))
{
break;
}
else
{
string rtfMessage=rtfConnMsgStart+Nick.Trim()+" vient de se connecter\par";
msg=System.Text.Encoding.UTF8.GetBytes(rtfMessage);
}
}
if(useLogging)
{
Logging(formattedMsg);
}
Thread forwardingThread=new Thread(new ThreadStart(writeToAll));
forwardingThread.Start();
forwardingThread.Join();
paquetsReceived++;
}
readLock=false;
}
}
}
Thread.Sleep(10);
}
}
}
public class forwardToAll
{
public ArrayList acceptList=new ArrayList();
public Hashtable MatchList=new Hashtable();
public forwardToAll(){}
public void sendMsg(byte[] msg)
{
for(int i=0;i<acceptList.Count;i++)
{
if(((Socket)acceptList[i]).Connected)
{
try
{
int bytesSent=((Socket)acceptList[i]).Send(msg,msg.Length,SocketFlags.None);
}
catch
{
Console.Write(((Socket)acceptList[i]).GetHashCode()+" déconnecté");
}
}
else
{
acceptList.Remove((Socket)acceptList[i]);
i--;
}
}
}
public void sendMsg(string message)
{
for(int i=0;i<acceptList.Count;i++)
{
if(((Socket)acceptList[i]).Connected)
{
try
{
byte[] msg=System.Text.Encoding.UTF8.GetBytes(message);
int bytesSent=((Socket)acceptList[i]).Send(msg,msg.Length,SocketFlags.None);
Console.WriteLine("Writing to:"+acceptList.Count.ToString());
}
catch
{
Console.Write(((Socket)acceptList[i]).GetHashCode()+" déconnecté");
}
}
else {
acceptList.Remove((Socket)acceptList[i]);
i--;
}
}
}
}
class MainClass
{
public static void Main(string[] args)
{
Server startIt=new Server();
if(args.Length>0)
{
if(args[0]=="-log" && args[1]=="true")
{
startIt.useLogging=true;
}
}
startIt.Start();
}
}
}
1.5. Le client
using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace chatClient
{
public class MainForm : System.Windows.Forms.Form
{
private System.Windows.Forms.TabPage Chat;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.RichTextBox msgArea;
private System.Windows.Forms.Button Save;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox Nick;
private System.Windows.Forms.TextBox ServerHost;
private System.Windows.Forms.Button sendMsg;
private System.Windows.Forms.RichTextBox chatBody;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TabPage Connexion;
private System.Windows.Forms.Button Connect;
private System.Windows.Forms.CheckBox Notif;
public Socket ClientSocket=null;
public Thread DataReceived=null;
private Thread Flasht = null;
public string NickName=null;
public long sequence=0;
public int numberMsg=0;
private bool allowBlink=false;
private const string rtfStart="{\\rtf1\\ansi\\ansicpg1252\\deff0\\
deflang1033{\\fonttbl{\\f0\\fswiss\\fcharset0 Arial;}{\\f1\\fswiss\\fprq2\\
fcharset0 Arial;}}{\\colortbl ;\\red0\\green0\\blue128;\\red0\\green128\\blue0;}\\viewkind4\\uc1";
private string rtfContent=null;
public MainForm()
{
InitializeComponent();
}
public static void Main(string[] args)
{
Application.Run(new MainForm());
}
#region Windows Forms Designer generated code
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(MainForm));
this.Notif = new System.Windows.Forms.CheckBox();
this.Connect = new System.Windows.Forms.Button();
this.Connexion = new System.Windows.Forms.TabPage();
this.label2 = new System.Windows.Forms.Label();
this.chatBody = new System.Windows.Forms.RichTextBox();
this.sendMsg = new System.Windows.Forms.Button();
this.ServerHost = new System.Windows.Forms.TextBox();
this.Nick = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.Save = new System.Windows.Forms.Button();
this.msgArea = new System.Windows.Forms.RichTextBox();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.Chat = new System.Windows.Forms.TabPage();
this.Connexion.SuspendLayout();
this.tabControl1.SuspendLayout();
this.Chat.SuspendLayout();
this.SuspendLayout();
this.Notif.BackColor = System.Drawing.Color.IndianRed;
this.Notif.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.Notif.Location = new System.Drawing.Point(16, 144);
this.Notif.Name = "Notif";
this.Notif.Size = new System.Drawing.Size(152, 24);
this.Notif.TabIndex = 12;
this.Notif.Text = "Faire clignoter la fenêtre";
this.Connect.BackColor = System.Drawing.Color.IndianRed;
this.Connect.ForeColor = System.Drawing.Color.WhiteSmoke;
this.Connect.Location = new System.Drawing.Point(16, 96);
this.Connect.Name = "Connect";
this.Connect.Size = new System.Drawing.Size(104, 23);
this.Connect.TabIndex = 6;
this.Connect.Text = "Se connecter";
this.Connect.Click += new System.EventHandler(this.Button2Click);
this.Connexion.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("Connexion.BackgroundImage")));
this.Connexion.Controls.Add(this.Notif);
this.Connexion.Controls.Add(this.Save);
this.Connexion.Controls.Add(this.Nick);
this.Connexion.Controls.Add(this.label2);
this.Connexion.Controls.Add(this.label1);
this.Connexion.Controls.Add(this.ServerHost);
this.Connexion.Controls.Add(this.Connect);
this.Connexion.Location = new System.Drawing.Point(4, 22);
this.Connexion.Name = "Connexion";
this.Connexion.Size = new System.Drawing.Size(528, 310);
this.Connexion.TabIndex = 1;
this.Connexion.Text = "Connexion";
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(16, 48);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(71, 16);
this.label2.TabIndex = 9;
this.label2.Text = "Votre pseudo";
this.chatBody.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.chatBody.Location = new System.Drawing.Point(0, 8);
this.chatBody.Name = "chatBody";
this.chatBody.ReadOnly = true;
this.chatBody.Size = new System.Drawing.Size(512, 192);
this.chatBody.TabIndex = 8;
this.chatBody.Text = "";
this.chatBody.TextChanged += new System.EventHandler(this.HandleAutoScroll);
this.sendMsg.BackColor = System.Drawing.Color.IndianRed;
this.sendMsg.ForeColor = System.Drawing.Color.WhiteSmoke;
this.sendMsg.Location = new System.Drawing.Point(208, 272);
this.sendMsg.Name = "sendMsg";
this.sendMsg.TabIndex = 5;
this.sendMsg.Text = "Envoyer";
this.sendMsg.Click += new System.EventHandler(this.SendMessage);
this.ServerHost.BackColor = System.Drawing.Color.LightGray;
this.ServerHost.Location = new System.Drawing.Point(160, 16);
this.ServerHost.Name = "ServerHost";
this.ServerHost.Size = new System.Drawing.Size(128, 20);
this.ServerHost.TabIndex = 7;
this.ServerHost.Text = "";
this.Nick.BackColor = System.Drawing.Color.LightGray;
this.Nick.Location = new System.Drawing.Point(160, 48);
this.Nick.Name = "Nick";
this.Nick.Size = new System.Drawing.Size(128, 20);
this.Nick.TabIndex = 10;
this.Nick.Text = "";
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(16, 16);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(130, 16);
this.label1.TabIndex = 8;
this.label1.Text = "Entrez le nom du serveur";
this.Save.BackColor = System.Drawing.Color.IndianRed;
this.Save.ForeColor = System.Drawing.Color.WhiteSmoke;
this.Save.Location = new System.Drawing.Point(160, 96);
this.Save.Name = "Save";
this.Save.Size = new System.Drawing.Size(216, 23);
this.Save.TabIndex = 11;
this.Save.Text = "Enregistrer les paramètres de connexion";
this.Save.Click += new System.EventHandler(this.SaveClick);
this.msgArea.Location = new System.Drawing.Point(0, 200);
this.msgArea.MaxLength = 2048;
this.msgArea.Name = "msgArea";
this.msgArea.Size = new System.Drawing.Size(512, 64);
this.msgArea.TabIndex = 9;
this.msgArea.Text = "";
this.tabControl1.Controls.Add(this.Chat);
this.tabControl1.Controls.Add(this.Connexion);
this.tabControl1.Location = new System.Drawing.Point(16, 16);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(536, 336);
this.tabControl1.TabIndex = 6;
this.Chat.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("Chat.BackgroundImage")));
this.Chat.Controls.Add(this.msgArea);
this.Chat.Controls.Add(this.chatBody);
this.Chat.Controls.Add(this.sendMsg);
this.Chat.Location = new System.Drawing.Point(4, 22);
this.Chat.Name = "Chat";
this.Chat.Size = new System.Drawing.Size(528, 310);
this.Chat.TabIndex = 0;
this.Chat.Text = "Chat";
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
this.ClientSize = new System.Drawing.Size(576, 389);
this.Controls.Add(this.tabControl1);
this.Name = "MainForm";
this.Text = "Chat";
this.Load += new System.EventHandler(this.MainFormLoad);
this.Activated += new System.EventHandler(this.StopBlink);
this.Deactivate += new System.EventHandler(this.StartBlink);
this.Closing += new System.ComponentModel.CancelEventHandler(OnClosing);
this.Connexion.ResumeLayout(false);
this.tabControl1.ResumeLayout(false);
this.Chat.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
[ DllImport("user32.dll") ]
static extern int FlashWindow
(
int hwnd,
int bInvert
);
private void Flash()
{
while(true) {
if(allowBlink)
{
FlashWindow((int)this.Handle, 1);
Thread.Sleep(500);
}
else
{
Thread.CurrentThread.Abort();
}
}
}
void StartBlink(object sender, System.EventArgs e)
{
allowBlink=true;
}
void StopBlink(object sender, System.EventArgs e)
{
allowBlink=false;
}
void SendMessage(object sender, System.EventArgs e)
{
if(ClientSocket==null || !ClientSocket.Connected)
{
MessageBox.Show("Vous n'tes pas connecté");
return;
}
try
{
if(msgArea.Text!="")
{
string reformattedBuffer=msgArea.Text.Replace("}","\\}");
reformattedBuffer=reformattedBuffer.Replace("\n","\\par\r\n");
SendMsg(GetSequence()+NickName+reformattedBuffer.Replace("{","\\{"));
msgArea.Clear();
}
}
catch(Exception E)
{
MessageBox.Show("SendMessage:"+E.Message);
}
}
void getParams()
{
if(File.Exists("params.ini"))
{
using(StreamReader SR=new StreamReader("params.ini"))
{
ServerHost.Text=SR.ReadLine();
Nick.Text=SR.ReadLine();
SR.Close();
}
}
}
void SendMsg(string message)
{
byte[] msg = System.Text.Encoding.UTF8.GetBytes(message);
int DtSent=ClientSocket.Send(msg,msg.Length,SocketFlags.None);
if(DtSent == 0)
{
MessageBox.Show("Aucune donnée n'a été envoyée");
}
}
private String GetAdr()
{
try
{
IPHostEntry iphostentry = Dns.GetHostByName(ServerHost.Text);
String IPStr = "";
foreach(IPAddress ipaddress in iphostentry.AddressList){
IPStr = ipaddress.ToString();
return IPStr;
}
}
catch(SocketException E)
{
MessageBox.Show(E.Message);
}
return "";
}
private void CheckData()
{
try
{
while(true)
{
if(ClientSocket.Connected)
{
if(ClientSocket.Poll(10,SelectMode.SelectRead) && ClientSocket.Available==0)
{
MessageBox.Show("La connexion au serveur est interrompue. Essayez avec un autre pseudo");
Connect.Enabled=true;
Thread.CurrentThread.Abort();
}
if(ClientSocket.Available>0)
{
string messageReceived=null;
if(Flasht==null)
{
if(allowBlink && Notif.Checked)
{
Flasht = new Thread(new ThreadStart(Flash));
Flasht.Start();
}
}
else
{
if(allowBlink && Notif.Checked && Flasht.IsAlive==false)
{
Flasht = new Thread(new ThreadStart(Flash));
Flasht.Start();
}
}
while(ClientSocket.Available>0)
{
try
{
byte[] msg=new Byte[ClientSocket.Available];
ClientSocket.Receive(msg,0,ClientSocket.Available,SocketFlags.None);
messageReceived=System.Text.Encoding.UTF8.GetString(msg).Trim();
rtfContent+=messageReceived;
}
catch(SocketException E)
{
MessageBox.Show("CheckData read"+E.Message);
}
}
try
{
chatBody.Rtf=rtfStart+rtfContent;
this.BringToFront();
}
catch(Exception E)
{
MessageBox.Show(E.Message);
}
}
}
Thread.Sleep(10);
}
}
catch
{
Thread.ResetAbort();
}
}
void SaveClick(object sender,System.EventArgs e)
{
if(Nick.Text != "" && ServerHost.Text != "")
{
using(StreamWriter SW=new StreamWriter("params.ini"))
{
SW.WriteLine(ServerHost.Text);
SW.WriteLine(Nick.Text);
SW.Close();
}
}
else {
MessageBox.Show("Veuillez saisir le nom du serveur et le pseudo");
}
}
void Button2Click(object sender, System.EventArgs e)
{
if(Nick.Text=="")
{
MessageBox.Show("Le pseudo ne peut tre null");
return;
}
if(ServerHost.Text=="")
{
MessageBox.Show("Le nom du serveur ne peut tre null");
return;
}
NickName=Nick.Text.Trim();
if(NickName.Length<15)
{
char pad=Convert.ToChar(" ");
NickName=NickName.PadRight(15,pad);
}
else if(NickName.Length > 15)
{
MessageBox.Show("Le pseudo doit tre de 15 caractères maximum");
return;
}
sequence=0;
IPAddress ip = IPAddress.Parse (GetAdr());
IPEndPoint ipEnd = new IPEndPoint (ip,8000);
ClientSocket=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
try
{
ClientSocket.Connect(ipEnd);
if(ClientSocket.Connected)
{
SendMsg(GetSequence()+NickName);
Connect.Enabled=false;
}
}
catch(SocketException E)
{
MessageBox.Show("Connection"+E.Message);
} try
{
DataReceived = new Thread(new ThreadStart(CheckData));
DataReceived.Start();
}
catch(Exception E)
{
MessageBox.Show("Démarrage Thread"+E.Message);
}
}
string GetSequence()
{
sequence++;
string msgSeq=Convert.ToString(sequence);
char pad=Convert.ToChar("0");
msgSeq=msgSeq.PadLeft(6,pad);
return msgSeq;
}
void HandleAutoScroll(object sender, System.EventArgs e)
{
chatBody.SelectionStart = chatBody.Rtf.Length;
chatBody.Focus();
msgArea.Focus();
}
private void OnClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
if(DataReceived!=null)
{
try
{
DataReceived.Abort();
DataReceived.Join();
}
catch(Exception E)
{
MessageBox.Show("Arrt Thread"+E.Message);
}
}
if(ClientSocket != null && ClientSocket.Connected)
{
try
{
ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Close();
if (ClientSocket.Connected) {
MessageBox.Show("Erreur: " + Convert.ToString(System.Runtime.InteropServices.Marshal.GetLastWin32Error()));
}
}
catch(SocketException SE)
{
MessageBox.Show("SE"+SE.Message);
}
}
}
void MainFormLoad(object sender, System.EventArgs e)
{
getParams();
}
}
}
2. Téléchargement
Le projet a été développé avec SharpDevelop, si vous désirez le modifier, le plus simple est de le faire avec SharpDevelop mais
rien ne vous empêche bien sûr de l'importer dans Visual Studio .NET. Téléchargez donc les deux zips:
Cet article est la propriété de www.developpez.com en tant qu'hebergeur ainsi que
celle de Stéphane Eyskens en tant que redacteur, ce texte est donc protégé par le code de la
propriété intellectuelle et est soumis à la réglementation en vigueur.
www.developpez.com ou son auteur se reserve le droit d'apporter des modifications
sans préavis. Vous pouvez utiliser cet article comme bon vous semble, faire un lien depuis
votre site Web, ou le copier en spécifiant l'auteur et la provenance (www.developpez.com)
Le non respect de cette règle equivaudrait à faire une contrefaon. La responsabilité de
www.developpez.com, de l'un de ses membres, ou de la direction ne pourra etre engagé en cas
de destruction partielle ou totale des données ou de l'architecture système ou logicielle
inhérente à l'utilisation des ses logiciels. Les logiciels decrits ici sont la propriété de
leurs auteurs respectifs.
|