Reputation: 2590
I'm trying to develop a console application behaving as an asynchronous socket client in C#. You can see the code below:
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());
}
}
}
When I'm debugging I see that the code does the work as expected but the memory size used by process is increasing every moment. I think that the reason of the memory leak is the following code piece:
receiveThread = new Thread((ThreadStart)delegate
{
while (true)
{
Receive(client);
receiveDone.WaitOne();
Thread.Sleep(1);
}
});
receiveThread.Start();
But I don't have any idea about the change I have to do. Do you have any tip?
Thanks in advance,
Upvotes: 1
Views: 2023
Reputation: 13495
I think the problem is in your Receive
method which you are calling in a while
loop. Basically you are creating a new StateObject
every time you loop around.
// Create the state object.
StateObject state = new StateObject();
Try and store the state object as a class variable and reuse it. Maybe add a Reset
method if you need to re-initialilze it again. This article shows a way to build a very efficient asynchronous socket which you may find useful.
Upvotes: 1