2014-10-28 45 views
0

我試圖在多線程環境中創建異步套接字客戶端,但它無法正常工作。 下面的示例代碼, 如果我創建新的AsyncSocketClient並從多線程環境調用StartClent,它將只處理一個或兩個休息,它不處理。(我創建新的AsyncSocketClient與每個新的請求) 是因爲的靜態變量,在多線程環境中創建c#異步套接字客戶端

class AsyncSocketClient 
    { 

     private static AutoResetEvent sendDone = 
      new AutoResetEvent(false); 
     private static AutoResetEvent receiveDone = 
      new AutoResetEvent(false); 

     private static ManualResetEvent connectDone = 
new ManualResetEvent(false); 

     static private String response = ""; 


     public void StartClent() 
     { 


      Socket workSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      // clientSock.ReceiveTimeout = 1; 


      try 
      { 
       workSocket.BeginConnect(new IPEndPoint(IPAddress.Loopback, 8080), new AsyncCallback(ConnectCallBack), workSocket); 
       connectDone.WaitOne(); 


       Send(s.workSocket, "<EOF>"); 
       sendDone.WaitOne(); 

       Receive(workSocket); 
       receiveDone.WaitOne(); 


      } 
      catch(Exception ex) 
      { 

      } 
     } 

     private void ConnectCallBack(IAsyncResult ar) 
     { 
      Socket workSocket = (Socket)ar.AsyncState; 
      workSocket.EndConnect(ar); 
      connectDone.Set(); 
     } 

     private void Receive(Socket client) 
     { 
      StateObject state = new StateObject(); 
      state.workSocket = client; 
      client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallBack), state); 
     } 

     private void ReceiveCallBack(IAsyncResult ar) 
     { 
      StateObject state = (StateObject)ar.AsyncState; 
      Socket client = state.workSocket; 

      int byteReceived= client.EndReceive(ar); 
      if (byteReceived > 0) 
      { 
       state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, state.buffer.Length)); 
       Array.Clear(state.buffer, 0, state.buffer.Length); 
       client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallBack), state); 
      } 
      else 
      { 
       if (state.sb.Length > 1) 
       { 
        response = state.sb.ToString(); 
       } 
       receiveDone.Set(); 
      } 
     } 

     private void Send(Socket client,string data) 
     { 
      byte[] sendBufer = Encoding.ASCII.GetBytes(data); 
      client.BeginSend(sendBufer, 0, sendBufer.Length, 0, new AsyncCallback(BeginSendCallBack), client); 

     } 

     private void BeginSendCallBack(IAsyncResult ar) 
     { 
      Socket client = (Socket)ar.AsyncState; 
      int byteSent= client.EndSend(ar); 
      Console.WriteLine("Sent {0} bytes to server.", byteSent); 
      sendDone.Set(); 
     } 



    } 

    public class StateObject 
    { 
     // Client socket. 
     public Socket workSocket = null; 
     // Size of receive buffer. 
     public const int BufferSize = 30; 
     // Receive buffer. 
     public byte[] buffer = new byte[BufferSize]; 
     // Received data string. 
     public StringBuilder sb = new StringBuilder(); 

    } 
+0

您的服務器實際上並不是異步的,因爲您正在執行阻止在這些靜態事件的所有地方等待。是的,他們很可能是你的問題的一部分。除了在看起來不應該分享的情況之外,你不應該被阻擋在第一位。 – Servy 2014-10-28 17:10:55

+0

@Servy這是根據MSDN。我們是否需要爲多線程環境中的每個請求創建一個新的套接字。 http://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx – user3597233 2014-10-28 17:20:27

+0

@ user3597233該示例對每個請求都需要新的套接字是正確的。雖然示例使用異步調用,因爲它立即阻止它實質上是同步的。您應該將發送和接收移動到回調中,以便StartClient不會阻止。您可能想要在紙上畫出正在發生的事情以及您的期望。 UML序列圖可能會有所幫助。 – 2014-10-28 17:45:24

回答

0

下面是一個非阻塞客戶端和服務器的一個簡單的回聲實現的例子。沒有錯誤檢查,沒有任何事情應該被正確地關閉。服務器有一些同步代碼,以方便跟蹤。

客戶

public class AsyncClient 
{ 
    private const int Port = 9999; 
    private readonly string _clientId; 
    private readonly Random _random; 

    public AsyncClient(int clientId) 
    { 
     _clientId = string.Format("Client Id: {0}", clientId); 
     _random = new Random(clientId); 
    } 

    public void StartClient() 
    { 
     try 
     { 
      var workSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      var state = new ClientState { WorkSocket = workSocket }; 
      workSocket.BeginConnect(new IPEndPoint(IPAddress.Loopback, Port), ConnectCallBack, state); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
    } 

    private void ConnectCallBack(IAsyncResult ar) 
    { 
     var state = (ClientState) ar.AsyncState; 
     state.WorkSocket.EndConnect(ar); 
     Send(state); 
    } 

    private void Receive(ClientState clientState) 
    { 
     clientState.WorkSocket.BeginReceive(clientState.Buffer, 0, ClientState.BufferSize, 0, ReceiveCallBack, clientState); 
    } 

    private void ReceiveCallBack(IAsyncResult ar) 
    { 
     var state = (ClientState) ar.AsyncState; 
     Socket client = state.WorkSocket; 
     int byteReceived= client.EndReceive(ar); 
     if (byteReceived > 0) 
     { 
      var receivedString = Encoding.UTF8.GetString(state.Buffer, 0, byteReceived); 
      Console.WriteLine("From Server: " + receivedString); 
      Array.Clear(state.Buffer, 0, state.Buffer.Length); 
      state.Count++; 
      Thread.Sleep(1000 + _random.Next(2000)); 
      Send(state); 
     } 
    } 

    private void Send(ClientState clientState) 
    { 
     Console.WriteLine("Sending " + _clientId); 
     byte[] buffer = Encoding.UTF8.GetBytes(string.Format("Send from Thread {0} Client id {1} Count {2}", Thread.CurrentThread.ManagedThreadId, _clientId,clientState.Count)); 
     clientState.WorkSocket.BeginSend(buffer, 0, buffer.Length, 0, BeginSendCallBack, clientState); 
    } 

    private void BeginSendCallBack(IAsyncResult ar) 
    { 
     var state = (ClientState) ar.AsyncState; 
     int byteSent= state.WorkSocket.EndSend(ar); 
     Console.WriteLine("Sent {0} bytes to server.", byteSent); 
     Receive(state); 
    } 
} 

public class ClientState 
{ 
    // Client socket. 
    public Socket WorkSocket = null; 
    // Size of receive buffer. 
    public const int BufferSize = 1024; 
    // Receive buffer. 
    public byte[] Buffer = new byte[BufferSize]; 

    public int Count = 0; 
} 

服務器

public class AsyncServer 
{ 
    private const int Port = 9999; 
    public void StartServer() 
    { 
     var thread = new Thread(Run) {IsBackground = true}; 
     thread.Start(); 
    } 

    private void Run() 
    { 
     Console.WriteLine("Running"); 
     var tcpListener = new TcpListener(IPAddress.Loopback, Port); 
     tcpListener.Start(); 
     while (true) 
     { 
      Console.WriteLine("Before Accept"); 
      var state = new ServerState {WorkSocket = tcpListener.AcceptSocket()}; 
      Console.WriteLine("Before Recieve"); 
      Receive(state); 
     } 
    } 

    private void Receive(ServerState state) 
    { 
     state.WorkSocket.BeginReceive(state.Buffer, 0, ServerState.BufferSize, 0, ReceiveCallBack, state); 
    } 

    private void ReceiveCallBack(IAsyncResult ar) 
    { 
     Console.WriteLine("ReceiveCallBack"); 
     var state = (ServerState) ar.AsyncState; 
     try 
     { 
      int byteReceived= state.WorkSocket.EndReceive(ar); 
      if (byteReceived > 0) 
      { 
       var receivedString = Encoding.UTF8.GetString(state.Buffer, 0, byteReceived); 
       Console.WriteLine("Received: " + receivedString); 
       var bytesToSend = Encoding.UTF8.GetBytes("Server Got --> " + receivedString); 
       Array.Copy(bytesToSend, state.Buffer, bytesToSend.Length); 
       state.WorkSocket.Send(state.Buffer, 0, bytesToSend.Length, SocketFlags.None); 
       Array.Clear(state.Buffer, 0, state.Buffer.Length); 
       Receive(state); 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e); 
     } 
    } 

    private class ServerState 
    { 
     public const int BufferSize = 1024; 
     public readonly byte[] Buffer = new byte[1024]; 
     public Socket WorkSocket; 
    } 

我一直在使用一個控制檯,您可以有兩個應用程序或只啓動客戶端和服務器單獨運行這一點。

static void Main(string[] args) 
    { 
     if (args.Length != 0) 
     { 
      var server = new AsyncServer(); 
      server.StartServer(); 
     } 
     else 
     { 
      for(int i = 0; i < 10; i++) 
      { 
       var client = new AsyncClient(i); 
       client.StartClient(); 
      } 
     } 
     Console.WriteLine("Press a key to exit"); 
     Console.ReadKey(); 
    } 
相關問題