Reputation: 143
I use a C# class for connection different child form. Project is MDI type. In the connection form, there is an Asynchronous Socket Listner called by thread. When I close my application, I can not close the listener and the program remains in task-manager. The problem is linked to opened listener. In form connection put this code:
private AsynchronousSocketListener socketListener; // Per socket in ascolto da parte delle App to Machine
private Thread t_listener;
public c_masterConn() //Costructor
{
socketListener = new AsynchronousSocketListener(); // Socketlistner async
t_listener = new Thread(socketListener.StartListening); // Thread for socketlistener
t_listener.Start(); // Start socketlistener
}
public void StopThr() //Stop listner thread
{
t_listener.Interrupt();
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public 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 void StopListening() // Stop Listening
{
allDone.Close();
}
}
In form child I put this:
private void hideMonBt_Click(object sender, EventArgs e)
{
this.Hide();
m_engMonitor.m_masterConn.StopThr(); // Stop "server"
}
private void c_frmMonitor_Load(object sender, EventArgs e)
{
m_engMonitor.socketConnect(); // Start "server" connection
}
I don't sure to use in connection form this code:
public void StopListening() // Stop Listening
{
allDone.Close();
}
public void StopThr() //Stop listner thread
{
t_listener.Interrupt();
}
What am I doing wrong? thanks.
Upvotes: 2
Views: 3326
Reputation: 143
I resolve the problem in this mode:
class c_masterConn
{
private AsynchronousSocketListener socketListener; // socketlistner
private Thread t_listener;
public c_masterConn() //Costructor
{
socketListener = new AsynchronousSocketListener(); // Socketlistner async
t_listener = new Thread(socketListener.StartListening); // Thread for socketlistener
t_listener.Start(); // Start socketlistener
}
public void StopConnection()
{
socketListener.StopListening();
}
// 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
{
Socket listener;
// Thread signal.
public ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public void AcceptCallback(IAsyncResult ar)
{
try
{ // 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);
}
catch (Exception ex)
{ }
}
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 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.
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 (ObjectDisposedException)
{
//Console.WriteLine("Listener closed.");
}
catch (Exception e)
{
//Console.WriteLine(e.ToString());
}
//Console.WriteLine("\nPress ENTER to continue...");
//Console.Read();
}
//...
public void StopListening() // Stop Listening
{
Socket exListener = Interlocked.Exchange(ref listener, null);
if (exListener != null)
{
exListener.Close();
}
}
}
I use the Sefe's solution but i modify when function "dispose" is called. I call StopListening function in the event "Form_close" of the father form. In this mode, the application close correctly.
Upvotes: 0
Reputation: 14007
The problem is that you never stop listening. You are running your socket in an endless loop and when you want to end it you are not closing the socket, but you are interrupting the thread. That's the equivalent of leaving your house by knocking down your door instead of opening it and closing it behind you.
In order to properly stop listening, you close the socket. BeginAccept
will throw an ObjectDisposedException
when this happens. There is no need at all to interrupt your thread:
public class AsynchronousSocketListener : IDisposable
{
Socket listener;
// Thread signal.
public ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public 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.
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 (ObjectDisposedException)
{
//Console.WriteLine("Listener closed.");
}
catch (Exception e)
{
//Console.WriteLine(e.ToString());
}
//Console.WriteLine("\nPress ENTER to continue...");
//Console.Read();
}
//...
public void StopListening() // Stop Listening
{
Socket exListener = Interlocked.Exchange(ref listener, null);
if (exListener != null)
{
exListener.Close();
}
}
public void Dispose()
{
StopListening();
}
}
When you want to end the listener, just call StopListening
. The thread will end normally when StartListening
exits.
Some other changes I made to your code:
AsynchronousSocketListener
disposable. You are wrapping a socket and you need to be sure it's freed when your listener is disposed.allDone
from static
to instance. If you would have multiple listeners (e.g. to different ports), they would share the event, which is a bug.What you still need to do: If you call StopListening
before StartListening
has assigned the value of listener
, listening will not stop. The listener will start normally. This is a race condition in your code which you have to eliminate.
Upvotes: 2