2013-02-20 41 views
11

Tôi chỉ mới bắt đầu lập trình Socket trong C# và bây giờ là một chút khó khăn với vấn đề này. Làm thế nào để bạn xử lý nhiều máy khách trên một máy chủ đơn lẻ mà không cần tạo một luồng cho mỗi máy khách?Lập trình Socket nhiều máy khách một máy chủ

Một chủ đề cho mỗi khách hàng hoạt động tốt khi có 10 khách hàng nói nhưng nếu số khách hàng lên đến 1000 khách hàng thì việc tạo một luồng cho mỗi đơn lẻ trong số họ được khuyến khích? Nếu có bất kỳ phương pháp khác để làm điều này có thể ai đó xin vui lòng tel cho tôi?

+1

Hãy thử http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod ... có một triệu bài viết xung quanh ở đó nếu bạn tìm kiếm 'ổ cắm async C# '.. – atlaste

+0

Có hàng trăm ví dụ nếu bạn google "giới thiệu về lập trình socket C#". Ngoài ra tải các video tuyệt vời của bạn về chủ đề nếu bạn thích điều đó. – MarcF

Trả lời

19

Cố gắng sử dụng máy chủ không đồng bộ. Chương trình ví dụ sau tạo một máy chủ nhận yêu cầu kết nối từ máy khách. Máy chủ được xây dựng với một ổ cắm không đồng bộ, do đó việc thực thi ứng dụng máy chủ không bị treo trong khi nó chờ kết nối từ máy khách. Ứng dụng nhận được một chuỗi từ máy khách, hiển thị chuỗi trên bàn điều khiển và sau đó lặp lại chuỗi đó cho máy khách. Chuỗi từ ứng dụng khách phải chứa chuỗi "" để báo hiệu kết thúc của thư.

using System; 
    using System.Net; 
    using System.Net.Sockets; 
    using System.Text; 
    using System.Threading; 

    // State object for reading client data asynchronously 
    public class StateObject { 
     // Client socket. 
     public Socket workSocket = null; 
     // Size of receive buffer. 
     public const int BufferSize = 1024; 
     // Receive buffer. 
     public byte[] buffer = new byte[BufferSize]; 
    // Received data string. 
     public StringBuilder sb = new StringBuilder(); 
    } 

    public class AsynchronousSocketListener { 
     // Thread signal. 
     public static ManualResetEvent allDone = new ManualResetEvent(false); 

     public AsynchronousSocketListener() { 
     } 

     public static void StartListening() { 
      // Data buffer for incoming data. 
      byte[] bytes = new Byte[1024]; 

      // Establish the local endpoint for the socket. 
      // The DNS name of the computer 
      // running the listener is "host.contoso.com". 
      IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); 
      IPAddress ipAddress = ipHostInfo.AddressList[0]; 
      IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); 

      // Create a TCP/IP socket. 
      Socket listener = new Socket(AddressFamily.InterNetwork, 
       SocketType.Stream, ProtocolType.Tcp); 

      // Bind the socket to the local endpoint and listen for incoming connections. 
      try { 
       listener.Bind(localEndPoint); 
       listener.Listen(100); 

       while (true) { 
        // Set the event to nonsignaled state. 
        allDone.Reset(); 

        // Start an asynchronous socket to listen for connections. 
        Console.WriteLine("Waiting for a connection..."); 
        listener.BeginAccept( 
         new AsyncCallback(AcceptCallback), 
         listener); 

        // Wait until a connection is made before continuing. 
        allDone.WaitOne(); 
       } 

      } catch (Exception e) { 
       Console.WriteLine(e.ToString()); 
      } 

      Console.WriteLine("\nPress ENTER to continue..."); 
      Console.Read(); 

     } 

     public static void AcceptCallback(IAsyncResult ar) { 
      // Signal the main thread to continue. 
      allDone.Set(); 

      // Get the socket that handles the client request. 
      Socket listener = (Socket) ar.AsyncState; 
      Socket handler = listener.EndAccept(ar); 

      // Create the state object. 
      StateObject state = new StateObject(); 
      state.workSocket = handler; 
      handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
       new AsyncCallback(ReadCallback), state); 
     } 

     public static void ReadCallback(IAsyncResult ar) { 
      String content = String.Empty; 

      // Retrieve the state object and the handler socket 
      // from the asynchronous state object. 
      StateObject state = (StateObject) ar.AsyncState; 
      Socket handler = state.workSocket; 

      // Read data from the client socket. 
      int bytesRead = handler.EndReceive(ar); 

      if (bytesRead > 0) { 
       // There might be more data, so store the data received so far. 
       state.sb.Append(Encoding.ASCII.GetString(
        state.buffer,0,bytesRead)); 

       // Check for end-of-file tag. If it is not there, read 
       // more data. 
       content = state.sb.ToString(); 
       if (content.IndexOf("<EOF>") > -1) { 
        // All the data has been read from the 
        // client. Display it on the console. 
        Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", 
         content.Length, content); 
        // Echo the data back to the client. 
        Send(handler, content); 
       } else { 
        // Not all data received. Get more. 
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
        new AsyncCallback(ReadCallback), state); 
       } 
      } 
     } 

     private static void Send(Socket handler, String data) { 
      // Convert the string data to byte data using ASCII encoding. 


     byte[] byteData = Encoding.ASCII.GetBytes(data); 

     // Begin sending the data to the remote device. 
     handler.BeginSend(byteData, 0, byteData.Length, 0, 
      new AsyncCallback(SendCallback), handler); 
    } 

    private static void SendCallback(IAsyncResult ar) { 
     try { 
      // Retrieve the socket from the state object. 
      Socket handler = (Socket) ar.AsyncState; 

      // Complete sending the data to the remote device. 
      int bytesSent = handler.EndSend(ar); 
      Console.WriteLine("Sent {0} bytes to client.", bytesSent); 

      handler.Shutdown(SocketShutdown.Both); 
      handler.Close(); 

     } catch (Exception e) { 
      Console.WriteLine(e.ToString()); 
     } 
    } 

    public static int Main(String[] args) { 
     StartListening(); 
     return 0; 
    } 
} 

Đó sẽ là giải pháp tốt nhất.

+0

Tôi đang sử dụng giải pháp này trong câu hỏi này, nhưng vì lý do nào đó, cuộc gọi lại không xảy ra ngay lập tức mà chỉ khoảng 20 giây sau đó. Bạn có thể kiểm tra xem nó? http://stackoverflow.com/questions/18418613/socket-buffers-the-data-it-receives –

+0

Giải pháp này không đầy đủ vì nó giả định bạn chỉ có một bộ điều hợp mạng. Nếu bạn có hai hoặc nhiều adapter mạng và bạn muốn nghe tất cả chúng thì giải pháp này không thành công. –

+0

allDone không hiển thị trong cuộc gọi lại. làm cho cuộc gọi lại của bạn sử dụng công cụ sửa đổi tĩnh. –

1

Chủ đề có thể hoạt động tốt nhưng hiếm khi có quy mô tốt với nhiều khách hàng đó. Có hai cách dễ dàng và nhiều cách phức tạp hơn để xử lý điều đó, đây là một số mã giả để biết hai cách dễ dàng hơn thường được cấu trúc để cung cấp cho bạn một cái nhìn tổng quan như thế nào.

chọn()

Đây là một cuộc gọi để kiểm tra ổ cắm có khách hàng mới hoặc dữ liệu chờ đợi vào chúng, một chương trình điển hình trông giống như thế này.

server = socket(), bind(), listen() 
while(run) 
    status = select(server) 
    if has new client 
     newclient = server.accept() 
     handle add client 
    if has new data 
     read and handle data 

Có nghĩa là không có chủ đề là cần thiết để xử lý nhiều khách hàng, nhưng nó không thực sự mở rộng quy mô cũng hoặc là nếu xử lý dữ liệu mất nhiều thời gian, sau đó bạn sẽ không đọc dữ liệu mới hoặc chấp nhận khách hàng mới cho đến khi đã xong .

Async socket

Đây là một cách khác để xử lý ổ cắm được loại trừu tượng trên chọn. Bạn chỉ cần thiết lập callbacks cho các sự kiện phổ biến và để cho framework thực hiện việc nâng cấp không quá nặng nề.

function handleNewClient() { do stuff and then beginReceive(handleNewData) } 
function handleNewData() { do stuff and then beginReceive(handleNewData) } 
server = create, bind, listen etc 
server.beginAddNewClientHandler(handleNewClient) 
server.start() 

Tôi nghĩ điều này sẽ tốt hơn nếu xử lý dữ liệu của bạn mất nhiều thời gian. Bạn sẽ làm loại xử lý dữ liệu nào?

0

This có thể là điểm khởi đầu tốt. Nếu bạn muốn tránh 1 sợi < -> 1 khách hàng; sau đó bạn nên sử dụng các cơ sở ổ cắm async được cung cấp trong .NET. Đối tượng cốt lõi để sử dụng ở đây là SocketAsyncEventArgs.

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