2014-12-31 37 views
1

我正在嘗試開發一個在C#中作爲異步套接字客戶端運行的控制檯應用程序。你可以看到下面的代碼:在套接字客戶端中增加內存使用量

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(); 
} 

class Program 
{ 
    private static readonly string hostIp = ConfigurationManager.AppSettings["HostIp"]; 
    private static readonly int port = Int32.Parse(ConfigurationManager.AppSettings["HostPort"]); 
    private static Socket client; 
    private static ManualResetEvent connectDone = new ManualResetEvent(false); 
    private static ManualResetEvent sendDone = new ManualResetEvent(false); 
    private static ManualResetEvent receiveDone = new ManualResetEvent(false); 
    private static Thread receiveThread; 

    static int Main(string[] args) 
    { 
     EventLog appLog = new EventLog(); 
     appLog.Source = "xApp"; 

     try 
     { 
      IPHostEntry ipHostInfo = Dns.GetHostEntry(hostIp); 
      IPAddress ipAddress = ipHostInfo.AddressList[0]; 
      IPEndPoint remoteEP = new IPEndPoint(ipAddress, port); 

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

      // Connect to the remote endpoint. 
      client.BeginConnect(remoteEP, 
       new AsyncCallback(ConnectCallback), client); 
      connectDone.WaitOne(); 

      // Send test data to the remote device. 
      Send(client, "Login Message"); 
      sendDone.WaitOne(); 

      receiveThread = new Thread((ThreadStart)delegate 
      { 
       while (true) 
       { 
        Receive(client); 
        receiveDone.WaitOne(); 
        Thread.Sleep(1); 
       } 
      }); 
      receiveThread.Start(); 
     } 
     catch (Exception ex) 
     { 
      appLog.WriteEntry(
       "An exception occured: " + 
       " ex: " + ex.ToString() + 
       " stack trace: " + ex.StackTrace, 
       System.Diagnostics.EventLogEntryType.Error); 
     } 

     return 0; 
    } 

    private static void Receive(Socket client) 
    { 
     try 
     { 
      // Create the state object. 
      StateObject state = new StateObject(); 
      state.workSocket = client; 

      // Begin receiving the data from the remote device. 
      client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
       new AsyncCallback(ReceiveCallback), state); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 
    } 

    private static void ReceiveCallback(IAsyncResult ar) 
    { 
     try 
     { 
      // Retrieve the state object and the client socket 
      // from the asynchronous state object. 
      StateObject state = (StateObject)ar.AsyncState; 
      Socket client = state.workSocket; 

      // Read data from the remote device. 
      int bytesRead = client.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)); 

       Console.WriteLine("Response received : {0}", state.sb.ToString()); 
       string[] args = state.sb.ToString().Split(';'); 
       switch (args[1]) 
       { 
        case "CREATEBOOK": 
         ProcessInput(args); 
         break; 
        case "CONFIRMBOOK": 
         if (args[2] == "true") 
         { 
          ConfirmProcess(); 
         } 
         break; 
        default: 
         break; 
       } 

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

    private static void Send(Socket client, String data) 
    { 
     byte[] byteData = Encoding.Unicode.GetBytes(data); 

     client.BeginSend(byteData, 0, byteData.Length, 0, 
      new AsyncCallback(SendCallback), client); 
    } 

    private static void SendCallback(IAsyncResult ar) 
    { 
     try 
     { 
      Socket client = (Socket)ar.AsyncState; 

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

      // Signal that all bytes have been sent. 
      sendDone.Set(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 
    } 

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

      // Complete the connection. 
      client.EndConnect(ar); 

      Console.WriteLine("Socket connected to {0}", 
       client.RemoteEndPoint.ToString()); 

      // Signal that the connection has been made. 
      connectDone.Set(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 
    } 
} 

當我調試我看到代碼做的工作如預期,但由進程使用的內存大小是增加的每一刻。我認爲內存泄漏的原因是以下代碼片:

receiveThread = new Thread((ThreadStart)delegate 
{ 
    while (true) 
    { 
     Receive(client); 
     receiveDone.WaitOne(); 
     Thread.Sleep(1); 
    } 
}); 
receiveThread.Start(); 

但是我對我必須做的改變沒有任何想法。你有小費嗎?

由於提前,

+1

爲什麼在總是等待結果時使用異步IO?這給你兩個世界中最糟糕的。 – usr

+0

您發佈的代碼中沒有任何內容會解釋_continuous_內存使用量的增加。由於GC的工作方式,在穩定之前可以看到內存使用量增加到某個點,這是完全正常和可接受的。但是請注意usr的評論:如果你要使用'BeginReceive()',你不應該在循環中等待I/O完成。相反,只需調用'BeginReceive()',然後從完成回調中再次調用它以開始下一次接收。如果您認爲自己有真正的內存泄漏問題,請發佈[一個很好的完整代碼示例](https://stackoverflow.com/help/mcve)。 –

回答

1

我認爲這個問題是在你Receive方法,您在while循環中調用。基本上,您每次循環時都會創建一個新的StateObject

// Create the state object. 
StateObject state = new StateObject(); 

嘗試並將狀態對象存儲爲類變量並重用它。如果您需要重新初始化,可能需要添加Reset方法。 This article展示了一種構建非常高效的異步套接字的方法,您可能會發現它很有用。