2013-01-10 12 views
5

Pisałem ten kod na mój serwer:Jak używać klienta TCP/nasłuchiwania w wielowątkowym C#?

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"; 
    } 

ten kod nasłuchiwanie żądań klienta w multi gwintowanych sposób. Nie jestem w stanie zrozumieć, w jaki sposób mogę odróżnić różnych klientów podłączonych do mojego serwera i który klient rozłącza się i żąda różnych poleceń.

mój kod klienta jest:

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; 

         } 
        } 
       } 
      } 
     } 
    } 
} 

ten fragment kodu łączy klienta z serwerem, ale nie jestem w stanie wysłać więcej wiadomości. Chcę w mojej aplikacji, jeśli klient jest podłączony, a następnie może wysyłać polecenia do serwera. zamiast tego to za każdym razem działać jako nowy klient na serwerze. Tęsknię za tym, uprzejmie poprowadź mnie we właściwym kierunku. Jestem całkowicie nowy w programowaniu sieciowym. Uprzejmie pomóż mi ulepszyć mój kod. Klient Tcp Listener i Tcp jest ważny dla tego scenariusza lub czy muszę używać gniazd?

+0

Nie powinieneś po prostu przełknąć swoich wyjątków za pomocą 'return', którego nie miałbyś pojęcia, gdyby coś poszło nie tak, przynajmniej wprowadzić jakąś formę logowania. –

+0

służy tylko do celów demonstracyjnych, – user1941098

+0

To wciąż zły nawyk, który warto wcześnie przerwać. Na osobnej uwadze dlaczego używasz 'ref' zamiast tylko przekazywać odpowiedź jako wartość zwracaną? –

Odpowiedz

3

Połączenie jest zamykane za każdym razem po stronie klienta po wysłaniu wiadomości, jeśli chcesz to zrobić, nie ma w tym nic złego, ale musisz wysłać do serwera pewną formę identyfikacji, aby można było stwierdzić, że nie jest nowym połączeniem, ale starym połączeniem nawiązującym połączenie po raz drugi. Jest to dokładnie to, co robi protokół HTTP, a "identyfikacja" to internetowe ciasteczka.

Pierwsza opcja jest w porządku, jeśli dane są wysyłane bardzo rzadko, ale jeśli robisz to częściej, zachowaj połączenie otwarte.

Po prostu musisz podjąć działanie polegające na podłączaniu i odłączaniu funkcji żądania klienta i przekazywać otwarte połączenie jako 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 
    } 
} 

Robiąc to w ten sposób po stronie serwera client obiekt reprezentuje klienta, trzeba będzie jedno wystąpienie go za połączonego klienta i pozostaną związane z tym klientem, dopóki nie rozłącza. Jeśli chcesz śledzić wszystkich podłączonych klientów, musisz wstawić je wszystkie do jakiejś kolekcji, takiej jak List<TcpClient> (albo użyj Concurrent Collection lub użyj blokowania, ponieważ jesteś wielowątkowy), a następnie będziesz mieć listę wszystkich klientów (będziesz musiał posprzątać klientów po sobie, aby usunęli się z listy po rozłączeniu).

+0

Zastanawiam się, skąd przejść klienta parametr do metody clientRequest? – user1941098

+0

Zakładam, że 'clientRequest' jest wywoływana z wewnątrz jakiejś formy pętli. Stworzysz połączenie przed pętlą i zamkniesz je po zakończeniu pętli. –

Powiązane problemy