Hi,
I start a new thread (previous one was "thread timing") because I have
isolated my problem.
It has nothing to do with calling unmanaged C++ code (I removed it in a
test application).
I have a thread "_itTaskThread" running.
The application is listening on a TCP port.
It accepts 2 connection from a client.
I simulate a crash on the client side (using "Debug->StopDebugging").
I got a "Sockets.SocketException" (as expected) but it seems to freeze
my "_itTaskThread" thread for more than 3 seconds !
Why does this thread is frozen, it has nothing to do with Tcp socket
handling !
See code + logs here below :
Thanks in advance for your help,
Droopy.
Application (WinForms with a "OK" push button)
Form1.cs
--------
....
private ManualResetEvent _itTaskEvent = new ManualResetEvent (false);
private TimeSpan _maxItTaskElapsedTime = TimeSpan.MinValue;
private TimeSpan _minItTaskElapsedTime = TimeSpan.MaxValue;
private Tcp _tcp;
private System.Windows.Forms.Button buttonOK;
private Thread _itTaskThread = null;
....
public Form1()
{
InitializeComponent();
_tcp = new Tcp ();
_tcp.OnCommandReceived += new Tcp.CommandReceivedHandler
(CommandReceivedHandler);
_itTaskThread = new Thread (new ThreadStart (ItTaskProc));
_itTaskThread.Name = "ItTask thread";
_itTaskThread.Priority = ThreadPriority.Highest;
_itTaskThread.Start ();
}
....
public void ItTaskProc ()
{
Util.TraceLine ("ItTaskProc thread started");
DateTime dtCurrent = DateTime.Now;
DateTime dtLast = DateTime.MinValue;
try
{
while (true)
{
Util.TraceLine ("before WaitOne");
if (_itTaskEvent.WaitOne (25, false))
{
Util.TraceLine ("ItTaskProc end asked");
break;
}
Util.TraceLine ("after WaitOne");
Util.TraceLine ("before ItTaskProc");
Util.TraceLine ("_serialChannel.ItTask ()");
Util.TraceLine ("after ItTaskProc");
dtLast = dtCurrent;
dtCurrent = DateTime.Now;
Util.TraceLine ("dtCurrent=" + dtCurrent.ToString ("HH:mm:ss:fff:
") +
", dtLast=" + dtLast.ToString ("HH:mm:ss:fff: "));
TimeSpan diff = dtCurrent.Subtract (dtLast);
if (_minItTaskElapsedTime > diff)
{
_minItTaskElapsedTime = diff;
Util.TraceLine ("New mininimum ItTaskElapsedTime = " +
_minItTaskElapsedTime);
}
if (_maxItTaskElapsedTime < diff)
{
_maxItTaskElapsedTime = diff;
Util.TraceLine ("New maximum ItTaskElapsedTime = " +
_maxItTaskElapsedTime);
}
}
}
catch(ThreadAbortException abortException)
{
Util.TraceLine ("ItTaskProc: Thread aborted");
}
catch (Exception ex)
{
Util.TraceLine ("ItTaskProc: Exception catched: " + ex);
}
finally
{
_itTaskEvent.Reset ();
}
Util.TraceLine ("ItTaskProc ended gracefully");
}
public bool CommandReceivedHandler (object sender, TcpInfoEventArgs
tcpInfo)
{
bool continueReading = true;
Util.TraceLine
("CommandCoordinator:CommandReceivedHandler tcpInfo = " + tcpInfo);
return continueReading;
}
private void CloseApp ()
{
_itTaskEvent.Set ();
_tcp.Close ();
}
private void buttonOK_Click(object sender, System.EventArgs e)
{
CloseApp ();
Application.Exit ();
}
Tcp.cs
------
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Text;
namespace IPRManaged
{
// publish/subscribe to export received command
// ---------- TcpInfoEventArgs ----------
public class TcpInfoEventArgs : EventArgs
{
private byte [] _buffer;
private int _bytesRead = 0;
public TcpInfoEventArgs (byte [] buffer, int bytesRead)
{
_buffer = buffer;
_bytesRead = bytesRead;
}
public override string ToString()
{
return "TcpInfoEventArgs #read = " + _bytesRead;
}
public int BytesRead
{
get { return _bytesRead; }
}
public byte [] Buffer
{
get { return _buffer; }
}
}
public class Tcp
{
private const int PORT = 1414;
private Socket _server;
private Thread _listeningThread = null;
private bool _mustRun = true;
private bool _continueReading = true;
// publish/subscribe to export received command
public delegate bool CommandReceivedHandler (object sender,
TcpInfoEventArgs tcpInfo);
public event CommandReceivedHandler OnCommandReceived;
// Thread signal.
private static ManualResetEvent _allDone = new ManualResetEvent
(false);
public Tcp ()
{
_listeningThread = new Thread (new ThreadStart (RunServer));
_listeningThread.Name = "TCP Listening thread";
_listeningThread.Start ();
}
public void Close ()
{
_mustRun = false;
_allDone.Set ();
// should not be needed
if (_listeningThread != null)
_listeningThread.Abort ();
}
public void RunServer ()
{
try
{
_server = new Socket
(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint (IPAddress.Any, PORT);
_server.Bind (iep);
_server.Listen (5);
Util.TraceLine ("TCP Server listening on port #" + PORT);
while (_mustRun)
{
// Set the event to nonsignaled state.
_allDone.Reset ();
_server.BeginAccept (new AsyncCallback (AcceptConnection),
_server);
// Wait until a connection is made before continuing.
_allDone.WaitOne ();
}
}
catch (Exception ex)
{
Util.TraceLine ("RunServer: Exception catched " + ex.Message);
}
_listeningThread = null;
Util.TraceLine ("RunServer: thread finished");
}
void AcceptConnection (IAsyncResult iar)
{
Socket server = (Socket) iar.AsyncState;
Socket client = server.EndAccept (iar);
Util.TraceLine ("TCP Server: connection accepted from client: " +
client.RemoteEndPoint.ToString() + " on " +
client.LocalEndPoint.ToString ());
// Signal the main thread to continue.
_allDone.Set ();
// Create the state object.
StateObject state = new StateObject ();
state.clientSocket = client;
Util.TraceLine ("Tcp:AcceptConnection: Accepting for client = " +
client.RemoteEndPoint.ToString () + " ...");
client.BeginReceive (state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback (ReadCallback), state);
}
public void ReadCallback (IAsyncResult ar)
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.clientSocket;
Util.TraceLine ("Tcp:ReadCallback: Receiving from client = " +
handler.RemoteEndPoint.ToString () + " ...");
try
{
// Read data from the client socket.
int bytesRead = handler.EndReceive (ar);
if (bytesRead > 0)
{
Util.TraceLine ("ReadCallback: " + bytesRead + " bytes received
for client = "
+ handler.RemoteEndPoint.ToString () +
" on " + handler.LocalEndPoint.ToString ());
StringBuilder iprlibIn = new StringBuilder ("IPRLIB:IN:");
for (int i = 0; i < bytesRead; i++)
{
iprlibIn.Append ("[" + i + "] = " + state.buffer [i].ToString
("X2") + " ");
}
Util.TraceLine (iprlibIn.ToString ());
if (OnCommandReceived == null)
Util.TraceLine ("TcpConnection:Run no subscriber defined to get
the command");
else
{
TcpInfoEventArgs tcpInfo = new TcpInfoEventArgs (state.buffer,
bytesRead);
_continueReading = OnCommandReceived (this, tcpInfo);
}
Util.TraceLine ("ReadCallback: continueReading = " +
_continueReading +
" for client = "
+ handler.RemoteEndPoint.ToString () +
" on " + handler.LocalEndPoint.ToString ());
if (_continueReading)
handler.BeginReceive (state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback (ReadCallback), state);
}
else
{
Util.TraceLine ("ReadCallback: no byte read, stop reading");
handler.Shutdown (SocketShutdown.Both);
handler.Close ();
handler = null;
}
}
catch (Exception ex)
{
Util.TraceLine ("ReadCallback: Exception catched: " + ex.ToString
());
}
if (handler != null)
Util.TraceLine ("ReadCallback: handling finished for client = "
+ handler.RemoteEndPoint.ToString () +
" on " + handler.LocalEndPoint.ToString ());
}
public 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);
Util.TraceLine ("SendCallback: Sent " + bytesSent + " bytes to
client = " +
handler.RemoteEndPoint.ToString () +
" on " + handler.LocalEndPoint.ToString ());
}
catch (Exception e)
{
Util.TraceLine (e.ToString());
}
}
}
// ---------- StateObject ----------
// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket clientSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte [BufferSize];
}
}
Logs (see the problem between 10:09:39:015 and 10:09:42:500)
----
....
10:09:38:984: ItTask thread: before WaitOne
10:09:39:000: ItTask thread: after WaitOne
10:09:39:000: ItTask thread: before ItTaskProc
10:09:39:000: ItTask thread: _serialChannel.ItTask ()
10:09:39:000: ItTask thread: after ItTaskProc
10:09:39:000: ItTask thread: dtCurrent=10:09:39:000: ,
dtLast=10:09:38:968:
10:09:39:000: ItTask thread: before WaitOne
10:09:39:015: : Tcp:ReadCallback: Receiving from client =
127.0.0.1:3417 ...
10:09:42:500: ItTask thread: after WaitOne
10:09:42:515: ItTask thread: before ItTaskProc
10:09:42:515: ItTask thread: _serialChannel.ItTask ()
10:09:42:515: ItTask thread: after ItTaskProc
10:09:42:515: ItTask thread: dtCurrent=10:09:42:515: ,
dtLast=10:09:39:000:
10:09:42:515: ItTask thread: New maximum ItTaskElapsedTime =
00:00:03.5156250
10:09:42:531: ItTask thread: before WaitOne
10:09:42:531: : ReadCallback: Exception catched:
System.Net.Sockets.SocketException: Une connexion existante a dû être
fermée par l'hôte distant
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at IPRManaged.Tcp.ReadCallback(IAsyncResult ar) in
c:\temp\testipr\windowsapplication\tcp.cs:line 157
10:09:42:531: : ReadCallback: handling finished for client =
127.0.0.1:3417 on 127.0.0.1:1414
10:09:42:531: : Tcp:ReadCallback: Receiving from client =
127.0.0.1:3416 ...
10:09:42:531: : ReadCallback: Exception catched:
System.Net.Sockets.SocketException: Une connexion existante a dû être
fermée par l'hôte distant
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at IPRManaged.Tcp.ReadCallback(IAsyncResult ar) in
c:\temp\testipr\windowsapplication\tcp.cs:line 157
10:09:42:531: : ReadCallback: handling finished for client =
127.0.0.1:3416 on 127.0.0.1:1414
10:09:42:546: ItTask thread: after WaitOne
10:09:42:546: ItTask thread: before ItTaskProc
10:09:42:546: ItTask thread: _serialChannel.ItTask ()
10:09:42:546: ItTask thread: after ItTaskProc
10:09:42:546: ItTask thread: dtCurrent=10:09:42:546: ,
dtLast=10:09:42:515:
....