2013-01-10 26 views
5

Tôi đã viết mã này cho máy chủ của tôi:Làm thế nào để sử dụng TCP client/listener trong đa luồng 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"; 
    } 

mã này lắng nghe yêu cầu của khách hàng một cách đa luồng. Tôi không thể hiểu làm thế nào tôi có thể phân biệt giữa các máy khách khác nhau được kết nối với máy chủ này của tôi và máy khách nào đang ngắt kết nối và yêu cầu các lệnh khác nhau.

mã khách hàng của tôi là:

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; 

         } 
        } 
       } 
      } 
     } 
    } 
} 

đoạn mã này kết nối khách hàng đến máy chủ, nhưng tôi không thể gửi tin nhắn nữa. Tôi muốn trong ứng dụng của tôi nếu khách hàng được kết nối sau đó ông có thể gửi lệnh đến máy chủ. thay vì làm điều này mỗi khi hành động như một khách hàng mới đến máy chủ. Tôi đang thiếu một số điều ở đây, Vui lòng hướng dẫn tôi đi đúng hướng. Tôi hoàn toàn mới để lập trình mạng C#. Vui lòng giúp tôi cải thiện mã của mình. Trình nghe Tcp và Trình khách Tcp hợp lệ cho kịch bản này hoặc tôi có cần sử dụng Ổ cắm không?

+0

Bạn không nên chỉ nuốt các ngoại lệ của mình với 'trả lại' mà bạn sẽ không biết nếu có điều gì đó sai, ít nhất hãy đưa vào một số hình thức ghi nhật ký. –

+0

của nó chỉ cho mục đích demo, – user1941098

+0

Nó vẫn là một thói quen xấu đó là tốt để phá vỡ sớm. Trên một lưu ý riêng biệt tại sao bạn sử dụng 'ref' thay vì chỉ chuyển trả lời dưới dạng giá trị trả về? –

Trả lời

3

Bạn đang đóng kết nối mỗi lần phía máy khách sau khi bạn gửi thư, nếu bạn muốn làm điều đó không có gì sai với nó nhưng bạn sẽ cần phải gửi một số hình thức nhận dạng đến máy chủ để nó có thể nói rằng điều này không phải là kết nối mới mà là kết nối cũ kết nối lần thứ hai. Đây là chính xác những gì các giao thức HTTP đang làm và rằng "nhận dạng" là cookie internet.

Tùy chọn đầu tiên đó là tốt nếu bạn truyền dữ liệu rất thường xuyên nhưng nếu bạn làm thường xuyên hơn, bạn cần giữ kết nối mở.

Cơ bản bạn cần thực hiện hành động kết nối và ngắt kết nối khỏi chức năng yêu cầu ứng dụng khách và chuyển kết nối mở dưới dạng đối số.

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

Bằng cách làm nó theo cách này phía máy chủ client đối tượng đại diện cho khách hàng, bạn sẽ có một thể hiện của nó mỗi khách hàng được kết nối và sẽ vẫn gắn liền với khách hàng rằng cho đến khi ông ngắt kết nối. Nếu bạn muốn theo dõi tất cả các máy khách được kết nối, bạn sẽ cần phải chèn tất cả chúng vào một số bộ sưu tập như List<TcpClient> (hoặc sử dụng Concurrent Collection hoặc sử dụng khóa vì bạn đa luồng) và sau đó bạn sẽ có danh sách tất cả các máy khách (bạn sẽ cần phải yêu cầu khách hàng dọn dẹp sau khi họ tự xóa mình khỏi danh sách sau khi ngắt kết nối).

+0

tôi tự hỏi, từ đâu để vượt qua khách hàng tham số cho phương thức clientRequest? – user1941098

+0

Tôi giả định rằng 'clientRequest' được gọi từ bên trong một số dạng vòng lặp. Bạn sẽ tạo kết nối trước vòng lặp và đóng nó sau khi vòng lặp kết thúc. –

Các vấn đề liên quan