2013-01-10 4 views
5

J'ai écrit ce code pour mon serveur:Comment utiliser client TCP/écouteur dans C# multithread?

using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using System.Threading.Tasks; 
    using System.Net; 
    using System.Threading; 
    using System.Net.Sockets; 
    using System.IO; 


namespace ConsoleApplication1 
{ 
    class Program 
    { 
     private static bool terminate; 

     public static bool Terminate 
     { 
      get { return terminate; } 
     } 

     private static int clientNumber = 0; 
     private static TcpListener tcpListener; 

     static void Main(string[] args) 
     { 
      StartServer(); 
      Console.Read(); 
     } 

     private static void StartServer() 
     { 
      try 
      { 
       Console.WriteLine("Server starting..."); 
       tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8000); 
       terminate = false; 
       tcpListener.Start(); 
       tcpListener.BeginAcceptTcpClient(ConnectionHandler, null); 
       Console.ReadLine(); 

      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.Message); 
      } 
      finally 
      { 
       Console.WriteLine("Server stopping..."); 
       terminate = true; 
       if (tcpListener != null) 
       { 
        tcpListener.Stop(); 
       } 
      } 
     } 

     private static void ConnectionHandler(IAsyncResult result) 
     { 
      TcpClient client = null; 

      try 
      { 
       client = tcpListener.EndAcceptTcpClient(result); 
      } 
      catch (Exception) 
      { 
       return; 
      } 

      tcpListener.BeginAcceptTcpClient(ConnectionHandler, null); 

      if (client!=null) 
      { 
       Interlocked.Increment(ref clientNumber); 
       string clientName = clientNumber.ToString(); 
       new ClientHandler(client, clientName); 
      } 
     } 
    } 
} 


    class ClientHandler 
    { 
     private TcpClient client; 
     private string ID; 

     internal ClientHandler(TcpClient client, string ID) 
     { 
      this.client = client; 
      this.ID = ID; 
      Thread thread = new Thread(ProcessConnection); 
      thread.IsBackground = true; 
      thread.Start(); 
     } 

     private void ProcessConnection() 
     { 
      using (client) 
      { 
       using (BinaryReader reader=new BinaryReader(client.GetStream())) 
       { 
        if (reader.ReadString()==Responses.RequestConnect) 
        { 
          using (BinaryWriter writer=new BinaryWriter(client.GetStream())) 
          { 
           writer.Write(Responses.AcknowledgeOK); 
           Console.WriteLine("Client: "+ID); 
           string message = string.Empty; 
           while (message!=Responses.Disconnect) 
           { 
            try 
            { 
             message = reader.ReadString(); 
            } 
            catch 
            { 
             continue; 
            } 
            if (message==Responses.RequestData) 
            { 
             writer.Write("Data Command Received"); 
            } 
            else if (message==Responses.Disconnect) 
            { 
             Console.WriteLine("Client disconnected: "+ID); 
            } 
            else 
            { 
             Console.WriteLine("Unknown Command"); 
            } 
           } 
          } 
        } 
        else 
        { 
         Console.WriteLine("Unable to connect client: "+ID); 
        } 
       } 
      } 
     } 
    } 

    class Responses 
    { 
     public const string AcknowledgeOK = "OK"; 
     public const string AcknowledgeCancel = "Cancel"; 
     public const string Disconnect = "Bye"; 
     public const string RequestConnect = "Hello"; 
     public const string RequestData = "Data"; 
    } 

ce code écouter les demandes des clients de manière multithread. Je n'arrive pas à comprendre comment je peux distinguer les différents clients connectés à mon serveur et quel client déconnecte et demande des commandes différentes.

mon code client:

private static void clietnRequest(string message,ref string response) 
{ 
    using (TcpClient client = new TcpClient()) 
    { 
     if (!client.Connected) 
     { 
      client.Connect(IPAddress.Parse("127.0.0.1"), 8000); 
      using (NetworkStream networkStream = client.GetStream()) 
      { 
       using (BinaryWriter writer = new BinaryWriter(networkStream)) 
       { 
        writer.Write(Responses.RequestConnect); 
        using (BinaryReader reader = new BinaryReader(networkStream)) 
        { 
         if (reader.ReadString() == Responses.AcknowledgeOK) 
         { 
          response = Responses.AcknowledgeOK; 

         } 
        } 
       } 
      } 
     } 
    } 
} 

ce morceau de code relie le client au serveur, mais je ne suis pas capable d'envoyer des messages plus. Je veux dans mon application si le client est connecté, il peut envoyer des commandes au serveur. Au lieu de le faire, il agit à chaque fois comme un nouveau client sur le serveur. Il me manque quelque chose ici, veuillez me guider dans la bonne direction. Je suis totalement nouveau à la programmation en réseau C#. Veuillez m'aider à améliorer mon code. Tcp Listener et Tcp Client sont valides pour ce scénario ou dois-je utiliser Sockets?

+0

Vous ne devriez pas simplement avaler vos exceptions avec un 'return' que vous n'auriez aucune idée si quelque chose s'est mal passé, au moins mis dans une forme de journalisation. –

+0

c'est juste pour le but de démo, – user1941098

+0

C'est encore une mauvaise habitude qui est bonne pour se casser tôt. Sur une note séparée, pourquoi utilisez-vous 'ref' au lieu de simplement passer la réponse comme valeur de retour? –

Répondre

3

Vous fermez la connexion chaque fois que vous envoyez un message à un client, si vous voulez faire cela, il n'y a rien de mal à cela, mais vous devrez envoyer une forme d'identification au serveur afin qu'il puisse dire que n'est pas une nouvelle connexion mais une ancienne connexion qui se connecte une seconde fois. C'est exactement ce que le protocole HTTP fait et que "l'identification" sont des cookies internet.

Cette première option est très bien si vous transmettez des données très rarement, mais si vous le faites plus souvent, vous devez garder la connexion ouverte. Fondamentalement, vous devez vous connecter et vous déconnecter de la fonction de demande client et passer la connexion ouverte en tant qu'argument.

private void MainCode() 
{ 
    using (TcpClient client = new TcpClient()) 
    { 
     client.Connect(IPAddress.Parse("127.0.0.1"), 8000); 

     while(variableThatRepresentsRunning) 
     { 
      //(Snip logic that gererates the message) 

      clietnRequest(message, ref response, client); 

      //(Snip more logic) 
     } 
    } 
} 

private static void clietnRequest(string message,ref string response, TcpClient client) 
{ 
    if (client.Connected) 
    { 
     using (NetworkStream networkStream = client.GetStream()) 
     { 
      using (BinaryWriter writer = new BinaryWriter(networkStream)) 
      { 
       writer.Write(Responses.RequestConnect); 
       using (BinaryReader reader = new BinaryReader(networkStream)) 
       { 
        if (reader.ReadString() == Responses.AcknowledgeOK) 
        { 
         response = Responses.AcknowledgeOK; 

        } 
       } 
      } 
     } 
    } 
    else 
    { 
     //Show some error because the client was not connected 
    } 
} 

En ce faisant de cette façon du côté du serveur d'objet client représente le client, vous aurez un cas de celui-ci par client connecté et demeurera associé à ce client jusqu'à ce qu'il se déconnecte. Si vous voulez suivre tous les clients connectés, vous devrez les insérer tous dans une collection comme List<TcpClient> (soit utiliser un Concurrent Collection ou utiliser le verrouillage parce que vous êtes multi-thread) et ensuite vous aurez une liste de tous les clients (vous devrez faire nettoyer les clients après eux-mêmes afin qu'ils se retirent de la liste après une déconnexion).

+0

Je me demande, d'où passer le client paramètre à la méthode clientRequest? – user1941098

+0

Je suppose que 'clientRequest' est appelé à l'intérieur d'une forme de boucle. Vous devez créer la connexion avant la boucle et la fermer après la fin de la boucle. –