[C#] Où trouver des tutos ?

Où trouver des tutos ? [C#] - C#/.NET managed - Programmation

Marsh Posté le 17-07-2004 à 02:30:10    

Ouais, je sais, google, mais je suis pas doué : soit je tombe sur des tutos super complexes, soit des trucs tellement basics que j'avance pas... Soit je trouve rien.
 
En gros, j'aimerais savoir comment faire :
- Un service
- Un pool de connection socket
- Plusieurs threads (pour le pool de ocnnections surtout)
 
En fait, je voudrais écrire un petit MUD tout simple. Pour ceux qui ne connaissent pas, il s'agit d'un type de jeu de rôle via telnet.
 
Le but serait de le faire tourner en tant que service, et pour le moment, simplement accepter plusieurs connections à la fois, et les faire inter-agir avec la routine principale.
 
Je suppose donc, pour le pool de connections, qu'il faut que je crée un thread qui écoute sur un port, et à chaque nouvelle connection, qu'il relance une nouvelle instance de lui-même, via une demande au process principal. J'ai bon ?
 
Pour le moment c'est super, j'ai trouvé un tuto pour faire un serveur qui répond a un port, quand je me connecte via telnet il me répond ce que je tape, c'est super :D Mais je vais pas aller loin avec ça :sweat:

Reply

Marsh Posté le 17-07-2004 à 02:30:10   

Reply

Marsh Posté le 17-07-2004 à 05:59:48    

y a pas mal de sources assez simples sur csharpfr.com.
Sinon tu peux trouver des cours de c# sur le site du labo .net   de supinfo, je sais qu'il y a notament une vidéo qui montre comment faire un service avec Visual.


---------------
Les hommes les plus riches du monde : #1.Bill Gates #5.Paul Allen #12.Larry Ellison #18.Michael Dell #19.Steve Ballmer #38.Pierre Omidyar #75.Gordon Moore #82.Jeffrey Bezos  #262.Steve Jobs
Reply

Marsh Posté le 17-07-2004 à 12:02:11    

Salut, je viens de trouver en effet les cours sur le site labo-donet, merci, je n'avais pas eu l'idée de voir de ca côté. (faut dire que la dernière fois que j'y étais allé, c'était plus orienté outils réseaux de Windows que .NET

Reply

Marsh Posté le 17-07-2004 à 18:51:13    

Pour le service et les connections assynchrones c'est ok.
Par contre, j'ai pas trouvé comment faire un pool de connections :sweat:
 
Il faut absolument que mon programme accepte un nombre "infini" de connections, sinon c'est mort :sweat:

Reply

Marsh Posté le 17-07-2004 à 19:15:12    

créer un thread pour chaque connexion entrante ça convient pas ?


---------------
Les hommes les plus riches du monde : #1.Bill Gates #5.Paul Allen #12.Larry Ellison #18.Michael Dell #19.Steve Ballmer #38.Pierre Omidyar #75.Gordon Moore #82.Jeffrey Bezos  #262.Steve Jobs
Reply

Marsh Posté le 17-07-2004 à 19:38:08    

le bon vieux select() est dispo en .NET: System.Net.Sockets.Socket.select()
je rappelle qu'il sert à gérer les IOS sur n sockets dans un seul thread.
vers la msdn


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 17-07-2004 à 21:19:42    

Bon, des nouvelles du front.
 
J'ai détruit mon ancien code (qui marchait bien pourtant), un programme en mode console avec une connexion simple.
A la place, j'ai créé un service windows tel qu'indiqué dans la vidéo sur supinfo. L'install a merdé, mais en bourrinant bien, j'ai fini par pouvoir l'installer.
 
Pour ce qui est du code à propos du cours sur les sockets...
 
Déjà, il est truffé de bugs. J'ai passé deux heures à essayer de savoir quel nom correspondait à quel hypothétique variable.
 
Ce que j'ai écrit compile, mais je doute que ça marche, et surtout, je ne vois pas trop ce que c'est censé pouvoir faire (à priori, ça devrait polluer mon eventlog et recopier tout ce que le serveur reçoit dedans. Pas terrible mais bon :D)
 
Seulement, je ne sais pas si c'est parceque c'est encore plus buggé que je ne l'imaginais, ou si c'est parceque je ne sais pas coder un webservice (ce qui est sûr), mais autant il démarre et s'arrête comme je lui demande sans planter, autant un telnet sur ma bécane reste muet.
 
Si une personne pouvait déjà me confirmer que mon service est censé "fonctionner"... Ca me permettrait de me concentrer sur ma class cSocket qui doit merder à plein tube...
 
Voici mon code (attention les mirettes, prenez une bassine au cas où vous auriez subitement des remontées gastriques) :
 
Service1.cs
 

Code :
  1. using System;
  2. using System.Collections;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Diagnostics;
  6. using System.ServiceProcess;
  7. using System.Net;
  8. using System.Net.Sockets;
  9. namespace MagicMUD
  10. {
  11. public class Service1 : System.ServiceProcess.ServiceBase
  12. {
  13.  /// <summary>  
  14.  /// Required designer variable.
  15.  /// </summary>
  16.  private System.ComponentModel.Container components = null;
  17.  public Service1()
  18.  {
  19.   // This call is required by the Windows.Forms Component Designer.
  20.   InitializeComponent();
  21.   // TODO: Add any initialization after the InitComponent call
  22.  }
  23.  // The main entry point for the process
  24.  static void Main()
  25.  {
  26.   System.ServiceProcess.ServiceBase[] ServicesToRun;
  27.   // More than one user Service may run within the same process. To add
  28.   // another service to this process, change the following line to
  29.   // create a second service object. For example,
  30.   //
  31.   //   ServicesToRun = new System.ServiceProcess.ServiceBase[] {new Service1(), new MySecondUserService()};
  32.   //
  33.   ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service1() };
  34.   System.ServiceProcess.ServiceBase.Run(ServicesToRun);
  35.   cSocket srv = new cSocket();
  36.   srv.StartListening();
  37.  }
  38.  /// <summary>  
  39.  /// Required method for Designer support - do not modify  
  40.  /// the contents of this method with the code editor.
  41.  /// </summary>
  42.  private void InitializeComponent()
  43.  {
  44.   components = new System.ComponentModel.Container();
  45.   this.ServiceName = "Service1";
  46.  }
  47.  /// <summary>
  48.  /// Clean up any resources being used.
  49.  /// </summary>
  50.  protected override void Dispose( bool disposing )
  51.  {
  52.   if( disposing )
  53.   {
  54.    if (components != null)
  55.    {
  56.     components.Dispose();
  57.    }
  58.   }
  59.   base.Dispose( disposing );
  60.  }
  61.  /// <summary>
  62.  /// Set things in motion so your service can do its work.
  63.  /// </summary>
  64.  protected override void OnStart(string[] args)
  65.  {
  66.   // TODO: Add code here to start your service.
  67.  }
  68.  /// <summary>
  69.  /// Stop this service.
  70.  /// </summary>
  71.  protected override void OnStop()
  72.  {
  73.   // TODO: Add code here to perform any tear-down necessary to stop your service.
  74.  }
  75. }
  76. }


 
socket.cs :
 

Code :
  1. using System;
  2. using System.Net;
  3. using System.Net.Sockets;
  4. using System.Diagnostics;
  5. using System.Threading;
  6. using System.Text;
  7. namespace MagicMUD
  8. {
  9. /// <summary>
  10. /// cSocket class provides interface for client connections.
  11. /// </summary>
  12. public class cSocket
  13. {
  14.  private static ManualResetEvent allDone = new ManualResetEvent(false);
  15.  Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  16.  public cSocket()
  17.  {
  18.  }
  19.  public void StartListening()
  20.  {
  21.   IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
  22.   IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0], 80);
  23.   if (EventLog.Exists("MagicMUD" ))
  24.   {
  25.    EventLog.WriteEntry("MagicMUD", "Server starts listening at " + localEP.ToString(), EventLogEntryType.Information);
  26.   }
  27.   Socket listener = new Socket(localEP.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  28.   try
  29.   {
  30.    listener.Bind(localEP);
  31.    s.Listen(100);
  32.    while (true)
  33.    {
  34.     allDone.Reset();
  35.     if (EventLog.Exists("MagicMUD" ))
  36.     {
  37.      EventLog.WriteEntry("MagicMUD", "Waiting for connection", EventLogEntryType.Information);
  38.     }
  39.     listener.BeginAccept(new AsyncCallback(acceptCallBack), listener);
  40.     allDone.WaitOne();
  41.    }
  42.   }
  43.   catch (Exception e)
  44.   {
  45.    if (EventLog.Exists("MagicMUD" ))
  46.    {
  47.     EventLog.WriteEntry("MagicMUD", "Error: " + e.ToString(), EventLogEntryType.Error);
  48.    }
  49.   }
  50.   if (EventLog.Exists("MagicMUD" ))
  51.   {
  52.    EventLog.WriteEntry("MagicMUD", "Server ends", EventLogEntryType.Information);
  53.   }
  54.   s.Shutdown(SocketShutdown.Both);
  55.   s.Close();
  56.  }
  57.  private static void acceptCallBack(IAsyncResult ar)
  58.  {
  59.   Socket listner = (Socket) ar.AsyncState;
  60.   Socket handler = listner.EndAccept(ar);
  61.   allDone.Set();
  62.   StateObject state = new StateObject();
  63.   state.workSocket = handler;
  64.   handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(readCallBack), state);
  65.  }
  66.  private static void readCallBack(IAsyncResult ar)
  67.  {
  68.   try
  69.   {
  70.    StateObject state = (StateObject) ar.AsyncState;
  71.    Socket client = state.workSocket;
  72.    int bytesRead = client.EndReceive(ar);
  73.    if (bytesRead > 0)
  74.    {
  75.     state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
  76.     client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(readCallBack), state);
  77.    }
  78.    else
  79.    {
  80.     if (state.sb.Length > 1)
  81.     {
  82.      string response = state.sb.ToString();
  83.      if (EventLog.Exists("MagicMUD" ))
  84.      {
  85.       EventLog.WriteEntry("MagicMUD", "Recieved: " + response, EventLogEntryType.Warning);
  86.      }
  87.     }
  88.     allDone.Set();
  89.    }
  90.   }
  91.   catch (Exception e)
  92.   {
  93.    if (EventLog.Exists("MagicMUD" ))
  94.    {
  95.     EventLog.WriteEntry("MagicMUD", "Server ends", EventLogEntryType.Information);
  96.    }
  97.   }
  98.  }
  99. }
  100. public class StateObject
  101. {
  102.  public Socket workSocket = null;
  103.  public const int BufferSize = 256;
  104.  public byte[] buffer = new byte[BufferSize];
  105.  public StringBuilder sb = new StringBuilder();
  106. }
  107. }

Reply

Marsh Posté le 17-07-2004 à 21:29:12    

:heink:
 
Ha si en fait ça tourne (pas fait exprès DU TOUT :D)
 
Par contre heu...
 
J'ai une exception qui atterri dans l'eventlog lors de l'appel de la ligne :
 
s.Listen(100);
 
Message :
Error: System.Net.Sockets.SocketException: Un argument non valide a été fourni
   at System.Net.Sockets.Socket.Listen(Int32 backlog)
   at MagicMUD.cSocket.StartListening()
 
 
C'est quoi le problème :??:


Message édité par Arjuna le 17-07-2004 à 21:29:37
Reply

Marsh Posté le 17-07-2004 à 22:03:14    

J'éai viré le s, et j'ai utilisé mon socket "lintener" à la place (parceque je comprends pas pourquoi ils font référence à ce "s", surtout qu'il n'est marqué que là dans le cours.
 
Maintenant, il n'accepte jamais les connections (le listen passe bien, mais dans la boucle "while (true)" mais ne rentre jamais dans le "listener.BeginAccept(new AsyncCallback(acceptCallBack), listener);"
 
Je ne sais pas à quoi c'est dû. En tout cas un telnet sur le service retourne une erreur comme quoi il est impossible de se connecter. Le service quand à lui reste stoïque dans sa bêtise, et ne plante pas ni ne lève la moindre erreur. Il reste juste bloqué là.
 
Ca me lourde bien... J'ai quand même passé la journée sur cette connerie, et vu que je suis perduadé que de toute façon ce code ne me sert à rien (faute de trouver mieu) le temps que je passe à trouver pourquoi ça merde ne me servira de toute façon à rien...
Corriger un code imbitable (car plus que mal expliqué dans le cours "l'exemple par de lui-même" => Biensûr oui je vois ça, Supinfo c'est pas pour moi ça c'est clair !) ne m'apporte rien quant à la compréhensio du fonctionnement des Sockets en mode asychrone, et à par me démotiver, je ne vois pas ce que ça pourrais faire...
 
Bon, sinon, j'ai réfléchit un peu (bah ouais ça m'arrive des fois).
Et je me demande... Je doute fortement que les sockets asychones me soit de la moindre utilité au final...
 
Tout ce que je veux, moi, c'est d'avoir un thread par connection. Après, du moment que ce thread envoie à la routine principale les informations reçues, ça ne me sert à rien de plus.
 
Quoique... Nan, si, ça m'est utile... Il faut que j'envoie au client telnet (donc via la connection) les modifications de son environement, donc je ne peux pas me contenter d'attendre comme un con qu'il fasse une action pour lui afficher qu'un mob est en train de l'attaquer en fait... :sweat:
 
Pffff... Un coup de main serait vraiment le bienvenu :cry:


Message édité par Arjuna le 17-07-2004 à 22:12:16
Reply

Marsh Posté le 17-07-2004 à 22:26:39    

c'est pas très dur tout ça.
 
ton expertise en dev ouaibe ne t'aidera pas là. Prends donc les choses humblement en partant du principe que t'es un newbie. Essaye juste dans un main() d'ouvrir une socket en écoute, puis teste avec telnet quand tu y sera parvenu. Après complexifie ton truc, ça va venir tout seul.


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 17-07-2004 à 22:26:39   

Reply

Marsh Posté le 17-07-2004 à 22:34:42    

Ca ca marche.
 
J'ai déjà fait des premiers tests avec une connection synchrone, et j'obtenais parfaitment ce que je voulais.
 
Seulement, moi j'ai besoin d'avoir une connection assynchrone afin de pouvoir envoyer des choses au client sans attendre d'action de sa part (si c'est bien ce que j'ai compris du mode synchorone) et surtout, j'ai besoin que plusieurs personnes se connectent à la fois, seulement j'ai trouvé nul part comment faire un pool de connection.
 
J'ai regardé l'instruction select, je vois ce qu'elle fait, mais je ne suis pas sûr qu'elle réponde à mon besoin. Une fois établie, la connection ne se ferme que lorsque l'utilisateur quite l'appli (contraîrement à un serveur HTTP par exemple qui se déconnecte aussitôt qu'il a chargé une page). Donc je n'ai pas le souci de réutiliser les sockets, mais il faut bien que j'en ai un par utilisateur connecté. Je compte mettre tout ce monde là dans des threads isolés (connection + infos sur le joueur)

Reply

Marsh Posté le 17-07-2004 à 22:41:20    

bon bien tu va devoir avoir un thread acceptant les demandes de connections entrantes, avec une "socket serveur". Cette socket serveur peut accepter n connections à la suite en bouclant autour de l'appel accept().
 
Ensuite, tu va avoir n thread pour écouter les n clients ayant chacun leur propre connection tcp/ip.
 
Les connectections tcp/ip sont full duplex, tu peux envoyer et recevoir dessus en même temps. Donc il n'y a pas de pb pour avoir un autre thread gérant la maj des infos clients ("les mecs en telnet" ).


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 17-07-2004 à 22:45:57    

ha bon ? ok, donc si j'ai plus d'assynchrone à gérer du côté de la connection, ça va être tout à coup bien plus facile :D
 
Merci pour ces infos.
 
Je vais donc me pencher sur les threads pour mieu en comprendre le fonctionnement. :jap:

Reply

Marsh Posté le 17-07-2004 à 22:51:22    

Il est possible de gérer tout avec un seul thread, en utilisant une boucle principale d'application, architecturée autour de l'appel à select().
 
Menfin la solution avec threads fait plus moderne, et gère automatiquement le load balacing dans le cas ou les traitements pour un client particulier prennent beaucoup de temps (ce qui évite de bloquer les autres...)


Message édité par schnapsmann le 17-07-2004 à 22:52:04

---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 17-07-2004 à 23:12:22    

Et surtout je vais faire tourner l'appli sur un bi-pro, donc il vaut mieu au moins deux threads pour en tirer parti ;)

Reply

Marsh Posté le 17-07-2004 à 23:15:47    

je doute que ce soit le cpu qui limite ton petit serveur de jeu  :whistle: , mais dans l'esprit tu as raison


---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 17-07-2004 à 23:44:16    

Ca peut rapidement dépendre.
Si j'ai le courrage d'aller jusqu'au bout (ça y'a rien de moins sûr, je viens une fois de plus de repartir de 0 parceque j'arrive a rien avec les threads) je compte faire fonctionner les mobs à la façon tamagoshi (ils auront leur propre vie, et agiront de leur propre chefs, comme les joueurs - achats/vente d'items, attaque d'autres mobs, gains d'xp, etc.) Ceci pourrait rapidement bouffer pas mal de CPU...
Mais bon, pour le moment c'est d'arriver à faire une saleté de routine à la noix qui veuille bien accepter deux connection telnet et ne pas les confondre :fou:

Reply

Marsh Posté le 18-07-2004 à 00:11:36    

Bon, là j'ai un peu de mal avec la logique des Services.
 
J'ai trouvé cet exemple de thread :
http://msdn.microsoft.com/library/ [...] torial.asp
 
Enfin un truc facile à comprendre.
 
Maintenant, dans mon Service, j'ai 3 méthodes par défaut :
 
OnStart()
Main()
OnStop()
 
D'après des traces, les trois procédures sont lancées (en toute logique) dans cet ordre. Le OnStop() ne le lançant que lorsque j'arrête le service.
 
Donc...
 
Le but du jeu, c'est de spliter l'exemple de façon à :
-> Lancer le thread dans le OnStart()
-> Arrêter le thread dans le OnEnd()
-> Et dans le main... Ben pas faire grand chose pour le moment.
 
Seulement, lorsque je mets mes objets oThread et oAplha en global, j'ai une erreur "machin denote a Field where a Class was expected"
 
Pas moyen de me défaire de cette erreur.
 
Comment faire ?
 
Je veux bien tout mettre dans le Main, du moins pour le OnStart() c'est pas gênant.
 
Mais à ce moment, comment le thread va-t-il être arrêté ? Il ne faut pas que je l'arrête tant que le service tourne... Donc je n'ai pas d'autre solution que de ne pas le tuer... Et compter sur le garbage collector pour le faire lorsque le service s'arrête :sweat:
 
Y'a pas plus propre ???


Message édité par Arjuna le 18-07-2004 à 00:12:11
Reply

Marsh Posté le 18-07-2004 à 00:39:01    

Bon, j'ai shooté me main, et ça marche (faut pas chercher à comprendre)
 
En fait, le main se lance au moment du stop, je sais pas à quoi il sert, sur la MSDN il n'est spécifié nul part...


Message édité par Arjuna le 18-07-2004 à 00:48:33
Reply

Marsh Posté le 18-07-2004 à 11:14:47    

YES ! Ca marche :bounce:
 
Alors, j'utilise ça :
 
-> Dans le OnStart du service, je démarre un thread qui lance le socket d'écoute.
 
-> Dans le thread, je boucle sur socket.Accept()
-> Pour chaque "session" créé par le Accept(), je lance un nouveau thread qui va se charger de communiquer avec le client.
 
Tout marche bien, j'ai mon service qui démarre, je peux me connecter à deux dessus, et ca marche :)
 
Par contre, depuis que j'ai mis du Socket dans mon service, je ne peux plus arrêter le service :sweat:
 
Faut que je fasse un "end task" dessus à chaque fois :sweat:
 
La méthode "Abort()" d'un thread, elle fait quoi au juste ?
Chaque Thread tourne sur un objet à lui, j'ai donc bien mis les destructeurs. Mais à priori c'est pas le destructeur de l'objet qui est lancé (c'est assez logique, puisqu'un thread porte sur une fonction, pas sur un objet)
 
Bref... Comment je shoot tout ça ?
 
Voilà des extraits de mon code, histoire que ce soit plus clair :
 
Service1.cs:

Code :
  1. namespace MagicMUD
  2. {
  3. public class Service1 : System.ServiceProcess.ServiceBase
  4. {
  5.  Thread oThread;
  6.  protected override void OnStart(string[] args)
  7.  {
  8.   EventLog.WriteEntry("MagicMUD", "Service launching", EventLogEntryType.Information, 1);
  9.   Server oServer = new Server();
  10.   oThread = new Thread(new ThreadStart(oServer.StartServer));
  11.   oThread.Start();
  12.   while (!oThread.IsAlive);
  13.  }
  14.  protected override void OnStop()
  15.  {
  16.   EventLog.WriteEntry("MagicMUD", "Service finishing", EventLogEntryType.Information, 4);
  17.   oThread.Abort();
  18.   oThread.Join();
  19.  }
  20. }
  21. }


 
Server.cs:

Code :
  1. using System;
  2. using System.Diagnostics;
  3. using System.Threading;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. using System.Text;
  7. namespace MagicMUD
  8. {
  9. public class Server
  10. {
  11.  private Socket s;
  12.  private Thread oThread;
  13.  public Server()
  14.  {
  15.  }
  16.  ~Server()
  17.  {
  18.   EventLog.WriteEntry("MagicMUD", "Je suis dans le destructeur du Server", EventLogEntryType.Information, 1001);
  19.   if (s.Connected)
  20.   {
  21.    s.Shutdown(SocketShutdown.Both);
  22.    s.Close();
  23.   }
  24.   if (oThread.IsAlive)
  25.   {
  26.    oThread.Abort();
  27.    oThread.Join();
  28.   }
  29.  }
  30.  public void StartServer()
  31.  {
  32.   s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  33.   IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
  34.   IPAddress ipAddress = ipHostInfo.AddressList[0];
  35.   IPEndPoint ipe = new IPEndPoint(ipAddress, 80);
  36.   try
  37.   {
  38.    s.Bind(ipe);
  39.    s.Listen(100);
  40.   }
  41.   catch (SocketException se)
  42.   {
  43.    EventLog.WriteEntry("MagicMUD", "Socket error : " + se.ToString(), EventLogEntryType.Error, 101);
  44.    return;
  45.   }
  46.   while (true)
  47.   {
  48.    Socket handler;
  49.    try
  50.    {
  51.     handler = s.Accept();
  52.     EventLog.WriteEntry("MagicMUD", "Nouvelle connection", EventLogEntryType.Information, 1002);
  53.    }
  54.    catch (SocketException se)
  55.    {
  56.     EventLog.WriteEntry("MagicMUD", "Socket error : " + se.ToString(), EventLogEntryType.Error, 102);
  57.     break;
  58.    }
  59.    if (handler.Connected)
  60.    {
  61.     Session oSession = new Session(handler);
  62.     oThread = new Thread(new ThreadStart(oSession.Run));
  63.     oThread.Start();
  64.    }
  65.    else
  66.    {
  67.     EventLog.WriteEntry("MagicMUD", "Error. Client disconnected before session starts", EventLogEntryType.Error, 103);
  68.     return;
  69.    }
  70.   }
  71.  }
  72. }
  73. public class Session
  74. {
  75.  private Socket handler;
  76.  public Session(Socket handler)
  77.  {
  78.   this.handler = handler;
  79.  }
  80.  ~Session()
  81.  {
  82.   if (this.handler.Connected)
  83.   {
  84.    this.handler.Shutdown(SocketShutdown.Both);
  85.    this.handler.Close();
  86.   }
  87.  }
  88.  public void Run()
  89.  {
  90.   string dataRcp = null;
  91.   while (true)
  92.   {
  93.    while (true)
  94.    {
  95.     byte[] bytes = new byte[256];
  96.     int bytesRec = handler.Receive(bytes);
  97.     dataRcp += Encoding.ASCII.GetString(bytes, 0, bytesRec);
  98.     if (dataRcp.IndexOf("\n" ) > -1)
  99.     {
  100.      break;
  101.     }
  102.    }
  103.    EventLog.WriteEntry("MagicMUD", "J'ai reçu ça : " + dataRcp, EventLogEntryType.Information, 1001);
  104.    byte[] msg = Encoding.ASCII.GetBytes(dataRcp);
  105.    handler.Send(msg);
  106.    if (dataRcp.IndexOf("quit" ) == 0)
  107.    {
  108.     EventLog.WriteEntry("MagicMUD", "Arrêt de la connection", EventLogEntryType.Information, 1003);
  109.     break;
  110.    }
  111.    dataRcp = null;
  112.   }
  113.   if (this.handler.Connected)
  114.   {
  115.    this.handler.Shutdown(SocketShutdown.Both);
  116.    this.handler.Close();
  117.   }
  118.  }
  119. }
  120. }


 
En fait, qu'il y ait eu une connection ou non au service, ca reste bloqué. Je pense donc c'est c'est au niveau du Accept() que ça coince.
 
Quand j'avais un exemple bête de Thread (sans socket), ça marchait. En effet, j'avais un thread qui faisait une boucle infinie, mais pourtant que je faisais Abort() dessus il s'arrêtait gentillement :sweat:

Reply

Marsh Posté le 18-07-2004 à 12:05:08    

Sinon, depuis le thread Server qui crée les thread Session, je voudrais stocker des références vers chaque thread Session, afin de pouvoir les retrouver facilement (histoire d'envoyer par exemple les notification de déplacement des autres joueurs)
 
Comment faire ? J'ai pensé à un tableau, mais il va rapidement y avoir des trous. Deplus, je ne sais pas si redimensionner un tableau à chaque nouvelle/fin de session est très heureux comme solution.
Y'a quoi comme objet qui pourrait faire ça ? Une sorte de collection que je pourrais atteindre avec "foreach" et ajouter/supprimer des éléments avec add() et delete()
 
Merci de votre aide :sweat:

Reply

Marsh Posté le 18-07-2004 à 12:25:07    

Vous connaissez pas un forum C# avec des gens qui répondent ? :sweat:
 
Merci quand même pour ceux qui m'ont répondu hein, je ne dénigre pas ce forum. Mais disons que les gens qui connaissent le C# ici ne sont pas très nombreux, et peu d'entre eux daignent me répondre (ou alors ne savent pas, je ne sais pas) et du coup je reste bloqué comme un con sur des conneries.
 
Oui, je sais, il faut aussi que je m'achète un bouquin.

Reply

Marsh Posté le 18-07-2004 à 14:41:23    

Désolé de pas pouvoir t'aider. J'ai jamais manipuler de thread/pool sous .Net.
Ce forum est plutot basé sur les open sources j'ai remarqué.
 
T'as essayé le forum du labo dotnet de supinfo (ki t'as été donné + haut) ou encore le forum de développez.com ?
C'est là où j'me tourné généralement pour des dév en .Net.


Message édité par catoun le 18-07-2004 à 14:44:13
Reply

Marsh Posté le 18-07-2004 à 15:02:30    

Sur le site de supinfo, j'ai essayé, mais aucune réponse.
 
Je suis allé sur csharp.com et j'ai posté sur leur forum.
J'ai eu des réponses (qui m'aident énormément, maintenant mon service s'arrête !)
Mais c'est un forum vb en fait, donc je vais pas continuer à poster dessus.
 
Là, j'ai un problème.
 
J'ai un objet global que j'instancie dans la fonction "OnStart".
 
Son desctructeur n'est jamais appelé, même lorsque j'arrête le service.
Dans le OnStop, j'ai essayé monObj = null; mais c'est sans effet. Comment détruire un objet ? (et donc forcer le destructeur à s'éxécuter avant que le GC ne le tue à la bourrin)
 
Je vais faire un tous sur developpez.com Mais de mémoire, je n'ai jamais eu de réponse là-bas :sweat:

Reply

Marsh Posté le 18-07-2004 à 15:27:29    

En fait, j'ai cette class par exemple :
 

Code :
  1. public class Session
  2. {
  3.  private Socket handler;
  4.  private Thread oThread;
  5.  public Session(Socket handler)
  6.  {
  7.   EventLog.WriteEntry("MagicMUD", "Création d'une nouvelle session", EventLogEntryType.Information, 1010);   this.handler = handler;
  8.   oThread = new Thread(new ThreadStart(this.Run));
  9.   oThread.Start();
  10.   while (!oThread.IsAlive);
  11.  }
  12.  ~Session()
  13.  {
  14.   EventLog.WriteEntry("MagicMUD", "Terminaisaon d'une session", EventLogEntryType.Information, 1010);
  15.   if (oThread.IsAlive)
  16.   {
  17.    oThread.Abort();
  18.    oThread.Join();
  19.   }
  20.   if (this.handler.Connected)
  21.   {
  22.    this.handler.Shutdown(SocketShutdown.Both);
  23.    this.handler.Close();
  24.   }
  25.  }
  26.  public void Run()
  27.  {
  28.   StringBuilder dataRcp = null;
  29.   while (true)
  30.   {
  31.    while (true)
  32.    {
  33.     byte[] bytes = new byte[256];
  34.     int bytesRec = handler.Receive(bytes);
  35.     dataRcp.Append(Encoding.ASCII.GetString(bytes, 0, bytesRec));
  36.     if (dataRcp.ToString().IndexOf("\n" ) > -1)
  37.     {
  38.      break;
  39.     }
  40.    }
  41.    EventLog.WriteEntry("MagicMUD", "J'ai reçu ça : " + dataRcp.ToString(), EventLogEntryType.Information, 1010);
  42.    byte[] msg = Encoding.ASCII.GetBytes(dataRcp.ToString());
  43.    handler.Send(msg);
  44.    if (dataRcp.ToString().IndexOf("quit" ) == 0)
  45.    {
  46.     EventLog.WriteEntry("MagicMUD", "Arrêt de la connection", EventLogEntryType.Information, 1011);
  47.     break;
  48.    }
  49.    dataRcp.Remove(0, dataRcp.Length);
  50.   }
  51.  }
  52. }


 
Lorsque j'appelle puis détruit un objet de ma class :
 

Code :
  1. Session mySess = new Session(handler);
  2. mySess = null;
  3. GC.Collect();


 
=> Dans l'eventlog, j'ai bien "Création d'une nouvelle session"
Si un client telnet se conencte, j'ai bien aussi "J'ai reçu ça : ..."
 
=> Mais je n'ai jamais "Terminaisaon d'une session" :sweat:
 
Actuellement, ca me prose un gros problème, parceque lorsque j'arrête mon service, tous les clients telnet restent connectés, ce qui prouve que j'ai une chiée de threads qui tournent encore car il n'ont été détruits ni par le destructeur, ni par le GC :cry:


Message édité par Arjuna le 18-07-2004 à 15:27:50
Reply

Marsh Posté le 18-07-2004 à 16:43:24    

On ne détruit pas un objet comme ça :monObj = null
 
légère explication sur les destructeurs en c# sur le site d'en bas:
 
http://www.zdnet.fr/builder/archit [...] 213,00.htm
 
 
Ou bien tu fais à la façon c++ ( ~Class ) qui équivaut aussi à "Finalize" en c#.


Message édité par catoun le 18-07-2004 à 16:45:15
Reply

Marsh Posté le 18-07-2004 à 16:47:19    

Quand j'appelle le Finalize() depuis une méthode "dispose" comme dans l'article MSDN, j'ai une erreur de compilation ma disant que je n'ai pas le droit de l'appeler directement :(

Reply

Marsh Posté le 18-07-2004 à 16:59:19    

j'sais pas si ça peut résoudre ton problème :
 
http://www.c-sharpcorner.com/Code/ [...] harpNS.asp

Reply

Marsh Posté le 18-07-2004 à 17:55:49    

c'est tout des articles que j'ai déjà lu :D
 
nan, y'a pas moyen, mes destructeurs ne sont jamais appelés.
 
tant pis, je laisse tomber, car même en reprenant un exemple basic avec une class simplissime, le destructeur ne se lance pas. Doit y avoir un truc au niveau du service qui fait qu'il ne passe par par le GC ou autre...
 
en tout cas, j'ai remarqué que dans le OnStop() de toute façon les objets ne sont plus visibles (ils tournent encore mais impossible de les atteindre)
 
puis les objets meurrent tous seuls au bout d'une dizaine de secondes.
 
on va dire que c'est très bien comme ça :)

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed