Bonjour, je suis en train de développer un jeu de type MUD (faire une recherche dans www.mud-connect.com pour plus d'infos).
Le jeu tourne donc en tant que sevice Windows, et attends des connections telnet.
Au départ, avant d'intégrer la partie des sockets, j'ai recopié l'exemle du tutorial de MSDN à propos des threads (mes sessions telnet sont dans des threads afin de ne pas bloquer l'éxécution de la routine principale du service)
En créant un thread dans le OnStart() du service, puis en le stopant avec Abort() puis Join() dans le OnStop() ca fonctionnait très bien (de même avec OnPause() et OnResume())
Seulement, depuis que mon thread contient des appels à Socket, il refuse de mourrir, je suis obligé de shooter le service via le gestionnaire des tâches pour arrêter le service.
Ci-dessous mon code :
Service1.cs:
Code :
namespace MagicMUD
{
public class Service1 : System.ServiceProcess.ServiceBase
{
Thread oThread;
protected override void OnStart(string[] args)
{
EventLog.WriteEntry("MagicMUD", "Service launching", EventLogEntryType.Information, 1);
Server oServer = new Server();
oThread = new Thread(new ThreadStart(oServer.StartServer));
oThread.Start();
while (!oThread.IsAlive);
}
protected override void OnStop()
{
EventLog.WriteEntry("MagicMUD", "Service finishing", EventLogEntryType.Information, 4);
oThread.Abort();
oThread.Join();
}
}
}
Server.cs:
Code :
using System;
using System.Diagnostics;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace MagicMUD
{
public class Server
{
private Socket s;
private Thread oThread;
public Server()
{
}
~Server()
{
EventLog.WriteEntry("MagicMUD", "Je suis dans le destructeur du Server", EventLogEntryType.Information, 1001);
if (s.Connected)
{
s.Shutdown(SocketShutdown.Both);
s.Close();
}
if (oThread.IsAlive)
{
oThread.Abort();
oThread.Join();
}
}
public void StartServer()
{
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint ipe = new IPEndPoint(ipAddress, 80);
try
{
s.Bind(ipe);
s.Listen(100);
}
catch (SocketException se)
{
EventLog.WriteEntry("MagicMUD", "Socket error : " + se.ToString(), EventLogEntryType.Error, 101);
return;
}
while (true)
{
Socket handler;
try
{
handler = s.Accept();
EventLog.WriteEntry("MagicMUD", "Nouvelle connection", EventLogEntryType.Information, 1002);
}
catch (SocketException se)
{
EventLog.WriteEntry("MagicMUD", "Socket error : " + se.ToString(), EventLogEntryType.Error, 102);
break;
}
if (handler.Connected)
{
Session oSession = new Session(handler);
oThread = new Thread(new ThreadStart(oSession.Run));
oThread.Start();
}
else
{
EventLog.WriteEntry("MagicMUD", "Error. Client disconnected before session starts", EventLogEntryType.Error, 103);
return;
}
}
}
}
public class Session
{
private Socket handler;
public Session(Socket handler)
{
this.handler = handler;
}
~Session()
{
if (this.handler.Connected)
{
this.handler.Shutdown(SocketShutdown.Both);
this.handler.Close();
}
}
public void Run()
{
string dataRcp = null;
while (true)
{
while (true)
{
byte[] bytes = new byte[256];
int bytesRec = handler.Receive(bytes);
dataRcp += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (dataRcp.IndexOf("\n") > -1)
{
break;
}
}
EventLog.WriteEntry("MagicMUD", "J'ai reçu ça : " + dataRcp, EventLogEntryType.Information, 1001);
byte[] msg = Encoding.ASCII.GetBytes(dataRcp);
handler.Send(msg);
if (dataRcp.IndexOf("quit") == 0)
{
EventLog.WriteEntry("MagicMUD", "Arrêt de la connection", EventLogEntryType.Information, 1003);
break;
}
dataRcp = null;
}
if (this.handler.Connected)
{
this.handler.Shutdown(SocketShutdown.Both);
this.handler.Close();
}
}
}
}
PS: Deplus, dans mon thread "Server", je voudrais stocket mes "Session", mais un tableau ne me semble pas terrible, car il va vite y avoir des trous (quand un joueur se déconnecte) et il faudra redimensionner le tableau à chaque nouvelle connection...
Y'a pas un objet collection avec "Add()" et "Remove()" accessible avec foreach ?
Je pense que ça pourrait résoudre en partie mon problème parceque de toute façon, actuellement, dès que je crée un thread "Session", je perds sa référence, donc impossible de le tuer proprement.
Ceci dit, le service refuse de s'arrêter même si aucune session n'a démarré donc...