I have a time consuming task that tests a couple of network connections. In my example below I have confined it to one connection.
Normally the connection returns quickly but it could happen that the connection cannot be made so that the socket times out. During this time I would like to display an "idler" gif in the Form, when the connection succeeds the app should change the Image in the Form to some
green check icon or in case of a failing connection a red icon "stopper" should be displayed.
Somehow I cannot get the idler gif become visible and animated. To simulate a failing connection one can enter an invalid port # or non existent address.
Any clues what I'm missing or doing wrong?
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
///
#region BackgroundWorker
private System.ComponentModel.BackgroundWorker backgroundWorker = new System.ComponentModel.BackgroundWorker();
private delegate void SomeLongRunningMethodHandler(object sender, EventArgs e);
#endregion
private System.ComponentModel.IContainer components = null;
Button button,button2;
static Socket socket;
static bool success;
private static bool done;
private Label lbl1;
private Label lbl2;
private TextBox address;
private TextBox port;
private PictureBox p;
private static String port_number,host;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void RunTest(object o,EventArgs e)
{
p.Visible = true;
SomeLongRunningMethodHandler synchronousFunctionHandler =
default(SomeLongRunningMethodHandler);
synchronousFunctionHandler =
TestConnection;
synchronousFunctionHandler.Invoke(o, e);
}
private void TestConnection(object o, EventArgs e)
{
host = address.Text;
port_number = port.Text;
if (null != socket)
{
socket.Close();
}
Thread.Sleep(1000);
IPEndPoint myEndpoint = new IPEndPoint(0, 0);
IPHostEntry remoteMachineInfo = Dns.GetHostEntry(host);
IPEndPoint serverEndpoint = new IPEndPoint(remoteMachineInfo.AddressList[0],
int.Parse(port_number));
socket = new Socket(myEndpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Connect(serverEndpoint);
success = true;
p.Image = global::BlockingUI.Properties.Resources.accept;
}
catch
{
success = false;
p.Image = global::BlockingUI.Properties.Resources.stopper;
}
done = true;
}
private void ExitApp(object o, EventArgs e)
{
Application.Exit();
}
}
If you truly want to use a BackgroundWorker, this (or something close to it), should point you in the right direction. You are creating a BackgroundWorker object but then doing nothing with it. BackgroundWorker objects are not allowed to access UI elements as they are owned by the UI thread, but you can pass in UI values, as I do here with a Tuple (you could create your own class to hold these values if you want too) and then modify the UI from the UI thread once the worker is complete.
private struct ConnectionProperties
{
public string Address;
public string Port;
}
private void RunTest(object o, EventArgs e)
{
BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
worker.RunWorkerCompleted += TestComplete;
worker.DoWork += TestConnection;
p.Visible = true;
//worker.RunWorkerAsync(new Tuple<string, string>(address.Text, port.Text));
worker.RunWorkerAsync(new ConnectionProperties{ Address = address.Text, Port = port.Text });
}
private void TestConnection(object sender, DoWorkEventArgs e)
{
bool success = false;
//var connection = e.Argument as Tuple<string, string>;
var connection = (ConnectionProperties)e.Argument;
if (null != socket)
{
socket.Close();
}
Thread.Sleep(1000);
IPEndPoint myEndpoint = new IPEndPoint(0, 0);
IPHostEntry remoteMachineInfo = Dns.GetHostEntry(connection.Address);
IPEndPoint serverEndpoint = new IPEndPoint(remoteMachineInfo.AddressList[0],
int.Parse(connection.Port));
socket = new Socket(myEndpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Connect(serverEndpoint);
success = true;
}
catch
{
success = false;
}
e.Result = success;
}
// Define other methods and classes here
private void TestComplete(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
var success = (bool)e.Result;
if (success)
{
p.Image = global::BlockingUI.Properties.Resources.accept;
}
else
{
p.Image = global::BlockingUI.Properties.Resources.stopper;
}
}
else
{
//unexpected error, show message or whatever
}
}
Well, I had done this with my own thread. Normally, you run the thread with the long running task, and when needed, call Control.Invoke() with a delegate pointing to a function that will operate over the UI. It looks that you're changing the UI using the background worker thread, which is not allowed.
Also, in Winforms is necessary to call Control.Invalidate() to force a re-painting of the UI and show the new icons.
Related
So my homework is to write a POP3 messaging software using tcp packets and im not allowed to use external libraries. I start the tcp connection when i press the Connect button and i also have a Disconnect button which stops it. I tested my server program with PuTTY and it works fine after the first connection but when i press Disconnect and Connect again it doesnt print the received data to the monitor. This problem is bothering me for ages please help. Here is my code:
Edit:
The problem was that i dont quite understand how threads work and i didnt create a new thread for each connection so i instantiated a new thread every time i created a new listener.
namespace POP3Server
{
public partial class MainWindow : Window
{
private TcpListener server;
private Int32 port;
private IPAddress ipAddress;
private TcpClient client;
private Logger log;
private Thread tcpAcceptThread;
private bool serverStarted;
public MainWindow()
{
InitializeComponent();
log = new Logger(txtConsole);
serverStarted = false;
tcpAcceptThread = new Thread(GetData);
}
private void btnConnect_Click(object sender, RoutedEventArgs e)
{
try
{
port = Convert.ToInt32(txtPort.Text);
ipAddress = IPAddress.Parse(txtIP.Text);
server = new TcpListener(ipAddress, port);
server.Start();
if (tcpAcceptThread.ThreadState != ThreadState.Unstarted)
tcpAcceptThread.Start();
serverStarted = true;
log.WriteLine("Server started!");
btnConnect.IsEnabled = false;
btnDisconnect.IsEnabled = true;
}
catch (Exception ex)
{
log.WriteLine(ex.ToString());
}
}
private void btnDisconnect_Click(object sender, RoutedEventArgs e)
{
try
{
if (client != null)
client.Close();
server.Stop();
log.WriteLine("Server stopped!");
serverStarted = false;
btnConnect.IsEnabled = true;
btnDisconnect.IsEnabled = false;
}
catch (Exception ex)
{
log.WriteLine(ex.ToString());
}
}
private void GetData()
{
try
{
while (serverStarted)
{
client = server.AcceptTcpClient();
this.Dispatcher.Invoke(() => log.WriteLine("Connected!"));
Byte[] bytes = new Byte[256];
String data = null;
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
this.Dispatcher.Invoke(() => log.WriteLine("Received: " + data));
}
}
}
catch (Exception ex)
{
this.Dispatcher.Invoke(() => log.WriteLine(ex.ToString()));
}
}
private void btnClear_Click(object sender, RoutedEventArgs e)
{
log.Clear();
}
}
}
Could you change following code
private bool serverStarted;
to:
private object _someLockObject = new object();
private bool _serverStarted = false;
private bool serverStarted {
get {
lock (_someLockObject)
{
return _serverStarted;
}
}
set {
lock (_someLockObject)
{
_serverStarted = value;
}
}
};
My first hunch is boolean property is not updated.
There is a Microsoft Docs example which shows how to use a BackgroundWorker. And in the sample code is this comment, followed by an access to the BackgroundWorker via a sender parameter:
// Do not access the form's BackgroundWorker reference directly.
// Instead, use the reference provided by the sender parameter.
BackgroundWorker bw = sender as BackgroundWorker;
What error or behavior is being avoided here? And is this always necessary? For example, if I have a background worker that I create apart from a form, will this still be a good practice?
Full example from the link reproduced here for convenience:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace BackgroundWorkerExample
{
public class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Do not access the form's BackgroundWorker reference directly.
// Instead, use the reference provided by the sender parameter.
BackgroundWorker bw = sender as BackgroundWorker;
// Extract the argument.
int arg = (int)e.Argument;
// Start the time-consuming operation.
e.Result = TimeConsumingOperation(bw, arg);
// If the operation was canceled by the user,
// set the DoWorkEventArgs.Cancel property to true.
if (bw.CancellationPending)
{
e.Cancel = true;
}
}
// This event handler demonstrates how to interpret
// the outcome of the asynchronous operation implemented
// in the DoWork event handler.
private void backgroundWorker1_RunWorkerCompleted(
object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
// The user canceled the operation.
MessageBox.Show("Operation was canceled");
}
else if (e.Error != null)
{
// There was an error during the operation.
string msg = String.Format("An error occurred: {0}", e.Error.Message);
MessageBox.Show(msg);
}
else
{
// The operation completed normally.
string msg = String.Format("Result = {0}", e.Result);
MessageBox.Show(msg);
}
}
// This method models an operation that may take a long time
// to run. It can be cancelled, it can raise an exception,
// or it can exit normally and return a result. These outcomes
// are chosen randomly.
private int TimeConsumingOperation(
BackgroundWorker bw,
int sleepPeriod )
{
int result = 0;
Random rand = new Random();
while (!bw.CancellationPending)
{
bool exit = false;
switch (rand.Next(3))
{
// Raise an exception.
case 0:
{
throw new Exception("An error condition occurred.");
break;
}
// Sleep for the number of milliseconds
// specified by the sleepPeriod parameter.
case 1:
{
Thread.Sleep(sleepPeriod);
break;
}
// Exit and return normally.
case 2:
{
result = 23;
exit = true;
break;
}
default:
{
break;
}
}
if( exit )
{
break;
}
}
return result;
}
private void startBtn_Click(object sender, EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync(2000);
}
private void cancelBtn_Click(object sender, EventArgs e)
{
this.backgroundWorker1.CancelAsync();
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
this.startBtn = new System.Windows.Forms.Button();
this.cancelBtn = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// backgroundWorker1
//
this.backgroundWorker1.WorkerSupportsCancellation = true;
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
//
// startBtn
//
this.startBtn.Location = new System.Drawing.Point(12, 12);
this.startBtn.Name = "startBtn";
this.startBtn.Size = new System.Drawing.Size(75, 23);
this.startBtn.TabIndex = 0;
this.startBtn.Text = "Start";
this.startBtn.Click += new System.EventHandler(this.startBtn_Click);
//
// cancelBtn
//
this.cancelBtn.Location = new System.Drawing.Point(94, 11);
this.cancelBtn.Name = "cancelBtn";
this.cancelBtn.Size = new System.Drawing.Size(75, 23);
this.cancelBtn.TabIndex = 1;
this.cancelBtn.Text = "Cancel";
this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(183, 49);
this.Controls.Add(this.cancelBtn);
this.Controls.Add(this.startBtn);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private System.ComponentModel.BackgroundWorker backgroundWorker1;
private System.Windows.Forms.Button startBtn;
private System.Windows.Forms.Button cancelBtn;
}
public class Program
{
private Program()
{
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
}
}
As #Hans Passant pointed out, sender and this.backgroundworker1 both reference the same object, and so do the same thing in the example. The reason for the warning is so if a future developer edits the backgroundWorker1_DoWork method to provide a different sender, sender will still work as intended, while this.backgroundworker1 might be accessing a backgroundworker which is no longer related to the method.
I'm experiencing a strange deadlock in the code that I've written.
The idea is to implement an asynchronous operation whose Stop is synchronous -- the caller has to wait until it completes. I've simplified the part where real work is done to a simple property increment (++Value, see below); in reality though, a heavy COM component is invoked which is very sensitive to threads.
The deadlock I'm experiencing is in the Stop() method where I explicitly wait for a manual-reset event that identifies a completed operation.
Any ideas what I could have done wrong? The code should be self-contained and compilable on its own.
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
using ThreadingTimer = System.Threading.Timer;
namespace CS_ManualResetEvent
{
class AsyncOperation
{
ThreadingTimer myTimer; //!< Receives periodic ticks on a ThreadPool thread and dispatches background worker.
ManualResetEvent myBgWorkerShouldIterate; //!< Fired when background worker must run a subsequent iteration of its processing loop.
ManualResetEvent myBgWorkerCompleted; //!< Fired before the background worker routine exits.
BackgroundWorker myBg; //!< Executes a background tasks
int myIsRunning; //!< Nonzero if operation is active; otherwise, zero.
public AsyncOperation()
{
var aTimerCallbac = new TimerCallback(Handler_Timer_Tick);
myTimer = new ThreadingTimer(aTimerCallbac, null, Timeout.Infinite, 100);
myBg = new BackgroundWorker();
myBg.DoWork += new DoWorkEventHandler(Handler_BgWorker_DoWork);
myBgWorkerShouldIterate = new ManualResetEvent(false);
myBgWorkerCompleted = new ManualResetEvent(false);
}
public int Value { get; set; }
/// <summary>Begins an asynchronous operation.</summary>
public void Start()
{
Interlocked.Exchange(ref myIsRunning, 1);
myTimer.Change(0, 100);
myBg.RunWorkerAsync(null);
}
/// <summary>Stops the worker thread and waits until it finishes.</summary>
public void Stop()
{
Interlocked.Exchange(ref myIsRunning, 0);
myTimer.Change(-1, Timeout.Infinite);
// fire the event once more so that the background worker can finish
myBgWorkerShouldIterate.Set();
// Wait until the operation completes; DEADLOCK occurs HERE!!!
myBgWorkerCompleted.WaitOne();
// Restore the state of events so that we could possibly re-run an existing component.
myBgWorkerCompleted.Reset();
myBgWorkerShouldIterate.Reset();
}
void Handler_BgWorker_DoWork(object sender, EventArgs theArgs)
{
while (true)
{
myBgWorkerShouldIterate.WaitOne();
if (myIsRunning == 0)
{
//Thread.Sleep(5000); //What if it takes some noticeable time to finish?
myBgWorkerCompleted.Set();
break;
}
// pretend we're doing some valuable work
++Value;
// The event will be set back in Handler_Timer_Tick or when the background worker should finish
myBgWorkerShouldIterate.Reset();
}
// exit
}
/// <summary>Processes tick events from a timer on a dedicated (thread pool) thread.</summary>
void Handler_Timer_Tick(object state)
{
// Let the asynchronous operation run its course.
myBgWorkerShouldIterate.Set();
}
}
public partial class Form1 : Form
{
private AsyncOperation myRec;
private Button btnStart;
private Button btnStop;
public Form1()
{
InitializeComponent();
}
private void Handler_StartButton_Click(object sender, EventArgs e)
{
myRec = new AsyncOperation();
myRec.Start();
btnStart.Enabled = false;
btnStop.Enabled = true;
}
private void Handler_StopButton_Click(object sender, EventArgs e)
{
myRec.Stop();
// Display the result of the asynchronous operation.
MessageBox.Show (myRec.Value.ToString() );
btnStart.Enabled = true;
btnStop.Enabled = false;
}
private void InitializeComponent()
{
btnStart = new Button();
btnStop = new Button();
SuspendLayout();
// btnStart
btnStart.Location = new System.Drawing.Point(35, 16);
btnStart.Size = new System.Drawing.Size(97, 63);
btnStart.Text = "Start";
btnStart.Click += new System.EventHandler(Handler_StartButton_Click);
// btnStop
btnStop.Enabled = false;
btnStop.Location = new System.Drawing.Point(138, 16);
btnStop.Size = new System.Drawing.Size(103, 63);
btnStop.Text = "Stop";
btnStop.Click += new System.EventHandler(Handler_StopButton_Click);
// Form1
ClientSize = new System.Drawing.Size(284, 94);
Controls.Add(this.btnStop);
Controls.Add(this.btnStart);
Text = "Form1";
ResumeLayout(false);
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
It seems like all you're trying to do is have an asynchronous task that starts with the press of a button and stops when another button is pressed. Given that, you seem to be over-complicating the task. Consider using something designed for cancelling an asynchronous operation, such as a CancellationToken. The async task simply needs to check the cancellation token's status in the while loop (as opposed to while(true)) and the stop method becomes as simple as calling cancel on the CancellationTokenSource.
private CancellationTokenSource cancellationSource;
private Task asyncOperationCompleted;
private void button1_Click(object sender, EventArgs e)
{
//cancel previously running operation before starting a new one
if (cancellationSource != null)
{
cancellationSource.Cancel();
}
else //take out else if you want to restart here when `start` is pressed twice.
{
cancellationSource = new CancellationTokenSource();
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
asyncOperationCompleted = tcs.Task;
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += (_, args) => DoWork(bgw, cancellationSource);
bgw.ProgressChanged += (_, args) => label1.Text = args.ProgressPercentage.ToString();
bgw.WorkerReportsProgress = true;
bgw.RunWorkerCompleted += (_, args) => tcs.SetResult(true);
bgw.RunWorkerAsync();
}
}
private void DoWork(BackgroundWorker bgw, CancellationTokenSource cancellationSource)
{
int i = 0;
while (!cancellationSource.IsCancellationRequested)
{
Thread.Sleep(1000);//placeholder for real work
bgw.ReportProgress(i++);
}
}
private void StopAndWaitOnBackgroundTask()
{
if (cancellationSource != null)
{
cancellationSource.Cancel();
cancellationSource = null;
asyncOperationCompleted.Wait();
}
}
put this code under ++Value; in Handler_BgWorker_DoWork. Then press the button when you see the output in debug window. Deadlock occurs then.
int i = 0;
while (i++ < 100) {
System.Diagnostics.Debug.Print("Press the button now");
Thread.Sleep(300);
Application.DoEvents();
}
I am using BackgroundWorker thread to call a small routine which is receiving messages from MSMQ as soon as the message comes to MSMQ queue(messages comes to msmq in every 5 seconds) it comes to my application which is using BackgroundWorker thread. Below is my Win Form class. I am new to threading so please appology if I am doing something wrong
Problem: My application is MDI application, when I am executing my application first time it works perfectly fine and receives the MSMQ message as soon as it comes to the queue, which is every 5 seconds but when ever I close this form which is a child form it closes fine, but right after opening this same form I am receiving messages from MSMQ with 10 seconds of dalay, so it means I am messing up something in the background worker thread, I tried to cancel this background worker thread but I am failed and unable to properly cancle or terminate the thread. Please help and share your experience. below is my form code.
public partial class FrmBooking : BookingManager.Core.BaseForm.BaseForm
{
internal const string queName = #"messageServer\private$\Response";
private Int32 counter = 0;
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
public FrmBooking()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.RunWorkerCompleted+=new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged+=new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.DoWork+=new DoWorkEventHandler(backgroundWorker1_DoWork);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bgWorker = sender as BackgroundWorker;
if (bgWorker.CancellationPending)
{
e.Cancel = true;
return;
}
try
{
MessageQueue messageQueue = null;
if (MessageQueue.Exists(queName))
{
messageQueue = new MessageQueue(queName);
}
else
{
MessageQueue.Create(queName);
}
messageQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
System.Messaging.Message msg = messageQueue.Receive();
bgWorker.ReportProgress(100, msg);
}
catch (Exception ex) { }
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
System.Messaging.Message msg = e.UserState as System.Messaging.Message;
listBoxControl1.Items.Add(msg.Body.ToString());
counter++;
labelControl1.Text = String.Format("Total messages received {0}", counter.ToString());
}
private void FrmBooking_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
}
You have two options here:
1) In the Form's Closing event, call backgroundWorker1.CancelAsync().
2) A better approach would be to remove your background worker altogether and use the the MessageQueue's native asynchronous processing mechanism for this. You can start the queue request using the BeginReceive method after adding a ReceivedCompleted event handler, then in the completed event handler, process the message and restart the request.
The issue is that if you issue a Receive request, it will block the background worker thread until a message is received in the queue, and CancelAsync will only request that the background worker be stopped, it won't cancel the Receive request.
For example (updated):
public partial class FrmBooking : BookingManager.Core.BaseForm.BaseForm
{
public FrmBooking()
{
InitializeComponent();
this.FormClosing += new FormClosingEventHandler(FrmBooking_FormClosing);
}
internal const string queName = #"messageServer\private$\Response";
private Int32 counter = 0;
private MessageQueue messageQueue = null;
private bool formIsClosed = false;
private void FrmBooking_Load(object sender, EventArgs e)
{
StartQueue();
}
void FrmBooking_FormClosing(object sender, FormClosingEventArgs e)
{
// Set the flag to indicate the form is closed
formIsClosed = true;
// If the messagequeue exists, close it
if (messageQueue != null)
{
messageQueue.Close();
}
}
private void StartQueue()
{
if (MessageQueue.Exists(queName))
{
messageQueue = new MessageQueue(queName);
}
else
{
MessageQueue.Create(queName);
}
messageQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
// Add an event handler for the ReceiveCompleted event.
messageQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(MessageReceived);
messageQueue.BeginReceive(TimeSpan.FromSeconds(15));
}
// Provides an event handler for the ReceiveCompleted event.
private void MessageReceived(Object source, ReceiveCompletedEventArgs asyncResult)
{
if (!this.formIsClosed)
{
// End the asynchronous receive operation.
System.Messaging.Message msg = messageQueue.EndReceive(asyncResult.AsyncResult);
// Display the message information on the screen.
listBoxControl1.Items.Add(msg.Body.ToString());
counter++;
labelControl1.Text = String.Format("Total messages received {0}", counter.ToString());
// Start receiving the next message
messageQueue.BeginReceive(TimeSpan.FromSeconds(15));
}
}
}
When you close the form, do you terminate the worker? If not, if there is a reference to the form or to the worker somewhere (event handlers?) then it will not get GCd and stays around. Upon opening the second instance you may have two background workers running....
Could you help me to get rid of this exception:
System.Net.Sockets.SocketException: "A blocking operation was
interrupted by a call to WSACancelBlockingCall"
What the below code does: sends UDP message to the server and fetches reply
(NAK or ACK)
Code that throws exception: m_receiveBytes = m_receiver.Receive(ref m_from);
Code:
public partial class _Default : System.Web.UI.Page
{
static readonly object lockScheduleIem = new object();
IPAddress m_AddressSend;
IPAddress m_AddressRecieve;
int m_groupPortSend;
int m_groupPortReceive;
IPEndPoint m_IPAddressSend;
IPEndPoint m_IPAddressReceive;
Byte[] m_receiveBytes;
Thread m_thread;
UdpClient m_receiver;
ManualResetEvent m_mre;
UdpClient m_sender;
IPEndPoint m_from;
protected void Page_Init(object sender, EventArgs e)
{
m_AddressSend = IPAddress.Parse("10.43.60.177");
m_AddressRecieve = IPAddress.Parse("10.43.60.99");
int.TryParse("60200", out m_groupPortSend);
int.TryParse("206", out m_groupPortReceive);
m_IPAddressSend = new IPEndPoint(m_AddressSend, m_groupPortSend);
m_IPAddressReceive = new IPEndPoint(m_AddressRecieve, m_groupPortReceive);
m_mre = new ManualResetEvent(false);
m_from = new IPEndPoint(IPAddress.Any, 0);
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
try
{
TimeSpan timeout;
timeout = new TimeSpan(0, 0, 0, 0, 5000);
m_sender = new UdpClient();
m_receiveBytes = null;
m_receiver = new UdpClient(m_IPAddressReceive);
m_thread = new Thread(new ThreadStart(ThreadProc));
m_thread.Start();
string str = string.Empty;
using (StreamReader sr = new StreamReader(#"C:\UDPmsgArchive\UDPmsg_Of_2011_10_18_13_7_33_968_634545400539687500.xml"))
str = sr.ReadToEnd();
byte[] XMLbytes = Encoding.ASCII.GetBytes(str);
m_sender.Send(XMLbytes, XMLbytes.Length, m_IPAddressSend);
m_mre.WaitOne(timeout, true);
m_mre.Reset();
m_receiver.Close();
if (m_receiveBytes != null)
Response.Write(Encoding.ASCII.GetString(m_receiveBytes, 0, m_receiveBytes.Length));
else
Response.Write("string.Empty");
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
}
public void ThreadProc()
{
try
{
m_receiveBytes = m_receiver.Receive(ref m_from); // ERROR HERE
m_mre.Set();
m_receiver.Close();
}
finally
{
m_mre.Set();
}
}
}
If I'm reading your code right, you're starting a thread to receive a UDP message. If it receives the message, it sets an event. The main thread starts the thread and then waits up to five seconds for the event to be set. If the event isn't set within that time, the main thread destroys the receiver that the thread is waiting on.
That's definitely going to throw an exception.
If you wait to eliminate the exception, modify your ThreadProc
try
{
// do stuff here
}
catch (SocketException) // or whatever the exception is that you're getting
{
}
I would suggest that you not include the m_mre.Set() call in a finally section. The main thread calls Reset on the event after the wait has completed, whether or not there is a timeout. If the thread calls Set in the finally, the the event's state will be set if a timeout occurs, because the following happens:
main thread calls Reset()
main thread calls Close() on the client
ThreadProc calls Set() in the finally
Instead, change your main thread code to look like this:
if (m_mre.WaitOne(timeout, true))
{
// event was set by the thread proc
// process the received data
// and reset the event
m_mre.Reset();
}
else
{
// A timeout occurred.
// Close the receiver
m_receiver.Close();
}
That said, you really don't have to spin up a thread to do this. Rather, you could use the asynchronous capabilities of UdpClient. Something like:
// Set timeout on the socket
m_receiver.Client.ReceiveTimeout = 5000;
try
{
IAsyncResult ir = m_receiver.BeginReceive(null, null);
m_receivedBytes = m_receiver.EndReceive(ir, m_receiver.Client.RemoteEndPoint);
// process received bytes here
}
catch (SocketException)
{
// Timeout or some other error happened.
}