在套接字客户端中增加内存使用量

在套接字客户端中增加内存使用量

问题描述:

我正在尝试开发一个在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://*.com/help/mcve)。 –

我认为这个问题是在你Receive方法,您在while循环中调用。基本上,您每次循环时都会创建一个新的StateObject

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

尝试并将状态对象存储为类变量并重用它。如果您需要重新初始化,可能需要添加Reset方法。 This article展示了一种构建非常高效的异步套接字的方法,您可能会发现它很有用。