first time using Stackoverflow so i'll try to do my best.
I was making a little app to ping some servers, the issue i'm having is that the GUI of the program locks up while it waits for a response.
This is what I have so far, Button_Click is the "Ping IP" button, ping_box is a textbox that will contain the response time, ip_address is a IP address in the form of a string.
private void Button_Click(object sender, RoutedEventArgs e)
{
Stopwatch s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromSeconds(2))
{
using (Ping p = new Ping())
{
ping_box.Text = (p.Send(ip_address, 1000).RoundtripTime.ToString() + "ms\n");
if (ping_box.Text == "0ms\n")
{
ping_box.Text = "Server is offline or exceeds 1000ms.";
}
}
}
s.Stop();
}
So in its current state it pings the IP address repeatedly for two seconds and puts the response time into a textbox, during this time the GUI locks up though.
I need to recorrect this as I want the textbox with the response time to update with each ping (if the response time is 500 ms then the textbox should update four times).
I've tried to use Ping.SendAsync but could not get it to work, any pointers or help would be much appreciated :)
I think this should help...
You can modify it further as per your needs
private void button1_Click(object sender, EventArgs e)
{
AutoResetEvent waiter = new AutoResetEvent(false);
IPAddress ip = IPAddress.Parse("192.168.1.2");
var pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;
pingSender.SendAsync(ip, 1000, waiter);
}
private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
// If an error occurred, display the exception to the user.
if (e.Error != null)
{
MessageBox.Show(string.Format("Ping failed: {0}", e.Error.ToString()),
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
DisplayReply(e.Reply);
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
public void DisplayReply(PingReply reply)
{
if (reply == null)
return;
ping_box.Text = string.Format("Ping status: {0}, RoundTrip time: {1}",
reply.Status,
reply.RoundtripTime.ToString());
}
Ping
Allows an application to determine whether a remote computer is
accessible over the network.
When you called Ping, your Main Thread (and that is your UI Thread) has been halt and wait for ping respond, that's why your application freeze.
solution:
You need to put Ping in another Thread
Related
I ran into problem while executing windows service in C#, not sure but probably due to the deadlock between the thread listening to the event handler and the normal code flow. The service just hangs when an event is listened and back to the normal flow where the Thread.Sleep is executed. The windows service goes into sleep mode normally in the first time, and in the next time the duration gets automatically doubled and thereafter it never wakes up and the service moves into a "Deadlock" mode.
There is one global variable in the below snippet controller.DeviceState, which is used both by the event listener and the main flow. All the exceptions are handled. Please let me know why the code just goes into "never waking sleep mode"
Below is the general code flow:
Main service
public partial class MainService : ServiceBase
{
protected override void OnStart(string[] args)
{
try
{
ThreadStart start = new ThreadStart(MainProcess);
Thread mainProcessThread = new Thread(start);
// set flag to indicate worker thread is active
serviceStarted = true;
// start threads
mainProcessThread.Start();
}
catch(Exception ex)
{
//catch exception
}
}
string testVariable = "YES";
//Event handler
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
System.IO.Ports.SerialPort sp = (System.IO.Ports.SerialPort)sender;
string s = sp.ReadExisting();
if (s == "Wifi")
{
testVariable = "NO";
}
}
private void MainProcess()
{
try
{
int i = 0;
System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort("COM4");
sp.Open();
sp.DataReceived += serialPort1_DataReceived;
sp.BaudRate = 9600;
sp.DataBits = 8;
sp.Parity = System.IO.Ports.Parity.None;
sp.StopBits = System.IO.Ports.StopBits.One;
sp.Handshake = System.IO.Ports.Handshake.None;
sp.DtrEnable = true;
while (testVariable == "YES")
{
i++;
//Sleep until the testVariable is set to NO
Thread.Sleep(5000);
}
}
catch(Exception ex)
{
//catch exception here
}
}
protected override void OnStop()
{
}
}
I think now i actually figured out what was causing the deadlock. In order to replicate, I increased the sleep time to 20 seconds and ran. What i found is, when a message is retrieved from the event handler during that period(sleep time) then the whole application goes to the hang mode, I don't understand the actual reason, but IMO the Thread.Sleep would also prevent any event handlers to listen and if it does then whole system would go to the "DEAD" mode.
To fix it, I initialized in the MainClass,
private static AutoResetEvent event_1 = new AutoResetEvent(true);
And added event_1.Set(); prior to Thread.Sleep as below:
while (testVariable == "YES")
{
Common.WriteLogIntoFile("i", i.ToString(), "FaxWorker()");
i++;
event_1.Set();
Thread.Sleep(20000);
}
But I don't know how it fixes it, if anyone knows it please let me know.
I'm trying to open a TCP/IP listener but when I run the code below, it crashes. It doesn't give me an error because when it crashes, it freezes and stops responding.
TcpListener server = new TcpListener(IPAddress.Any, 619);
TcpClient client;
private void button3_Click(object sender, EventArgs e)
{
server.Start();
client = server.AcceptTcpClient();
if (client.Connected)
{
MessageBox.Show("connected");
}
}
I know for a fact this port is free so that's not it. it crashes on this line:
client = server.acceptTcpClient();
You're executing a blocking call on the UI thread which gives the appearance of a "Crashing" application.
You need to use another thread or do things asynchronously. Background worker might be a starting point.
private BackgroundWorker bgw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
bgw.DoWork += Bgw_DoWork;
bgw.RunWorkerCompleted += Bgw_RunWorkerCompleted;
bgw.WorkerSupportsCancellation = true;
}
private void button3_Click(object sender, EventArgs e)
{
if (!bgw.IsBusy)
{
bgw.RunWorkerAsync();
((Button)sender).Content = "Cancel";
}
else
{
bgw.CancelAsync();
}
}
private void Bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button.Content = "Start";
}
private void Bgw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
var server = new TcpListener(IPAddress.Any, 619);
server.Start();
while (true)
{
if (worker.CancellationPending)
{
e.Cancel = true;
server.Stop();
break;
}
else
{
if (server.Pending())
{
var client = listener.AcceptTcpClient();
// handle client here or do something like below to return the client to the RunWorkerCompleted method in
// e.result
e.Result = client;
break;
}
}
}
}
There are other options such as using server.AcceptTcpClientAsync() instead of polling the server.Pending() property. Also, polling in this way without using Thread.Sleep in between may be overkill, i.e., you're checking the property very frequently and wasting cycles.
Following all of that, you need to figure out a way to deal with the client in a way that makes sense for your application. One click per client accepted? Handle new connections forever as they arrive until you cancel the listener? Etc. Good luck
BackgroundWorker tutorial
AcceptTcpClientAsync MSDN
This is expected behaviour. Your program hasn't crashed - the call to AccpetTcpClient() blocks waiting for an incoming connection:
https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.accepttcpclient(v=vs.110).aspx
You need to also open a TCP connection to port 619 from another thread, then your program will continue to run.
AcceptTcpClient is a blocking method
(https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.accepttcpclient%28v=vs.110%29.aspx).
When you call AcceptTcpClient, it will wait until a connection is made. Because it waits on the main thread (where also the GUI is running on), it will look like the program is frozen. Try using AcceptTcpClientAsync or putting the accepting part in a different thread. That should solve your problem.
Desirius
I'm working on a program that's supposed to establish "n" many SSH connections with a remote Linux server, and run time consuming commands on each connection. The "time consuming operation" is basically running a script that sets up Wireshark and listens to the traffic.
For this I'm using the SharpSSH library for C# and n many BackgroundWorkers as threads. Also for simplicity, the code below has n=2 BGW threads and SSH connections.
Code:
// runs when start is pressed
private void startButton_Click_1(object sender, EventArgs e)
{
sb = new StringBuilder();
DateTime timeNow = DateTime.Now;
clickTime = timeNow.ToString("yyyyMMddhhmmssfff"); // store the exact time of the click
bw = bwArray[0];
int index = 0; // ignore these 2 constants
foreach (BackgroundWorker bgw in bwArray)
{
if (bgw.IsBusy != true)
{
bgw.RunWorkerAsync();
// runWorkerAsync for every BackgroundWorker in the array
//index++;
}
}
}
// runWorkerAsync leads the BGWorker to this function
private void bw_doWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (worker.CancellationPending == true)
{
e.Cancel = true;
}
else
{
// let the UI know of button changes
int p = 0;
object param = "something"; // use this to pass any additional parameter back to the UI
worker.ReportProgress(p, param);
// UI notifying part ends here
// for the simplex case
if (numberOfConnections == 1)
startOperation();
// for the multiplex case
else if (numberOfConnections > 1)
{
//while (p < numberOfConnections)
//{
multiStartOperation();
// p++;
//}
}
Thread.Sleep(500);
}
}
// will be called for all ssh connections (in multiplex case)
private void multiStartOperation()
{
string[] command1Array = { "host2", "host2" };
string[] command2Array = { clickTime + "_h2", clickTime + "_h2" };
for (int index = 0; index < numberOfConnections; index++)
{
// shellArray is an array of SshExec objects
shellArray[index] = new SshExec(IPAddress, username, password);
try
{
shellArray[index].Connect();
}
catch (JSchException se)
{
Console.Write(se.StackTrace);
System.Windows.Forms.MessageBox.Show("Couldn't connect to the specified port.", "Connection Error!");
}
sb.Append(shellArray[index].RunCommand(command1Array[index]) + Environment.NewLine);
// first command is host3, or host4 etc.
// below is the time consuming command to run
string command = "./logcap.sh -c " + command2Array[index] + " -z";
// sb is a global stringBuilder object,
// to which the command output is appended
sb.Append(shellArray[index].RunCommand(command));
}
}
My problem is the following:
When I press the start button on the GUI, both connections should start and run the script. Whereas in the code given above, the first index of shellArray (which consists of SshExec objects) gets connected, prepares the commands and runs the time consuming command, at which point the program goes back to the UI, without even starting the second connection. This is obviously because of the for loop, but I couldn't figure out how to work around this yet.
I need to get the other backgroundworker to establish and run the second command with the second server, so that when I press the stop button on the GUI all connections and threads can stop all together.
PS: The commands will not stop running unless the user clicks stop, which sends a Ctrl-C signal to the server.
I'm relatively new to all the multithreading and networking concepts, so if there is any confusion or mistake please let me know.
Have a nice day.
Thank you for your answers, and the welcome. :)
The problem indeed was not being able to run multiple backgroundworkers at the same time.
I managed to solve the issue. It turns out that all I had to figure out was how to assign backgroundworkers to SSH connections. To do that, I created a class as follows:
class BGW
{
private BackgroundWorker bgw;
private int index;
//getters, setters, constructors...
}
After this, I converted bwArray which was an array of BackgroundWorkers into an array of BGW objects. At initialization, I assigned each BGW object an index.
Instead of having the stupid loop within multiStartOperation(), I sent an integer parameter to multiStartOperation() and that function used that index to reach the allocated backgroundworker.
So far it seems to work.
Have a nice day.
Every time I had problem with my SQL Server connection (ex. someone switch of server) my application will show an exception message in a messagebox. I don't know when will the connection available except I keep trying to open the connection / execute a query.
So I create a wait form that will appear if connection is unavailable, keep trying to open the connection, and close itself when connection is available again.
To hide the freeze from user, I use a background worker.
This is the background worker code
private void StartLoader(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 10; i++)
{
if (this.par.sqSuccess) //if no error, means connection is available, stop looping
{
break;
}
else
{
i -= 1;
}
System.Threading.Thread.Sleep(5000); //report progress every 5 second
}
This is the background worker's progress changed event
this.cnn = new SqlConnection(this.par.Constr);
try
{
this.cnn.Open(); //SqlConnection
this.par.sqSuccess = true; //if no error, then I change this variable
}
catch (Exception ex)
{
this.par.Exception = ex.Message;
}
finally
{
if (this.cnn != null) { this.cnn.Dispose(); }
}
if (this.par.sqSuccess) { this.Close(); }
After everything is complete, I tried to stop SQL Server service from services.msc, then I try to connect.
The wait form will appear and keep doing its job.
A few second after I try to connect, I start the service again and the wait form did close, success.
This is the problem, when I wait a little bit longer before I start the service again, the wait form still closed, but it takes a while.
After I check everything, it seems like the cnn.open() queue up and the longer I stop the service, the longer it takes for the wait form to close.
I searched google and try to add Connect Timeout=3; behind my connection string, as I'm sure my thread.sleep(5000) won't make them queue up, but still not working.
Someone told me to use cnn.OpenAsync();
After reading the documentation about OpenAsync, this is what I do.
static async Task<ConnectionState> Method(SqlConnection cnn)
{
await cnn.OpenAsync();
return cnn.State;
}
And this
private void SQLClientLoader_Load(object sender, EventArgs e)
{
do
{
this.cnn = new SqlConnection(this.par.Constr);
try
{
ConnectionState cst = Method(cnn).Result;
if (cst == ConnectionState.Open)
{
this.par.sqSuccess = true;
}
else
{
}
}
catch (Exception ex)
{
this.par.sqSuccess = false;
this.par.Exception = ex.Message;
}
finally
{
}
} while ((bool)this.par.sqSuccess != true);
}
The code above freezes my application every time the form load code executed.
I need simple instruction of how to wait for the cnn.Open process to finish or to cancel it if it takes too long.
Thank you in advance
You can set the ConnectionTimeout property for your SqlConnection in your code or in your ConnectionString. No need to use Async IMHO..
cnn.ConnectionTimeout = 5000
So this will create about a 10-second delay if connection does not work (connectiontimeout + Sleep(5000).
I have a problem using Thread.sleep(seconds), it pauses all my execution in sleeping state. But I tried another solutions also using for loop, however what I'm expecting it's not working.
When the login button is clicked:
Action report="on progressing";
After another 2 seconds it will be "trying to connect to the database"
then after opening database it will be like "database connected successfully"
Here is the code:
private void Loginbtn_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if(userText.Text!=String.Empty && passText.Password!=String.Empty){
ProgressForm.Visibility = System.Windows.Visibility.Visible;
LoginForm.Visibility = System.Windows.Visibility.Hidden;
delay(2);
actionReport.Text = "Try to Connecting the database";
String ConnectionString = "server=127.0.0.1;uid=root;pwd='';database=smsdb;";
MySqlConnection con = new MySqlConnection(ConnectionString);
try {
con.Open();
delay(2);
actionReport.Text = "Database Connected Sucessfully";
}
catch(MySqlException sqle){
actionReport.Text = sqle.Message;
}
}
else {
MessageBox.Show("Please enter the user name and password to verify","Notification",MessageBoxButton.OK,MessageBoxImage.Information);
}
}
private void delay(int seconds)
{
for(long i=0;i<seconds*3600; i++){
//empty
}
Please someone help me.
await (introduced in C# 5.0) with Task.Delay makes this trivially easy:
public async void Loginbtn_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
actionReport.Text = "Trying to Connecting to the database";
await Task.Delay(2);
actionReport.Text = "Connected";
}
For a C# 4.0 solution it's a tad messier, but not a whole lot:
public async void Loginbtn_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
actionReport.Text = "Trying to Connecting to the database";
Task.Delay(2).ContinueWith(_ =>
{
actionReport.Text = "Connected";
}, CancellationToken.None
, TaskContinuationOptions.None
, TaskScheduler.FromCurrentSynchronizationContext());
}
The key point here is that at no point are you blocking the UI thread, you're simply letting the UI thread continue on processing events for two seconds before giving it something to do.
I found answer like this
delay("Try to Connecting the database");
delay like this.
public void delay(string message) {
var frame = new DispatcherFrame();
new Thread((ThreadStart)(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(2));
frame.Continue = false;
})).Start();
Dispatcher.PushFrame(frame);
actionReport.Text=message;
}
Thanks friends!
to reply me.
You first need to look up and understand performing processing on a background thread. The main rules being;
You should never block the UI
don't try to talk to the UI thread from a background thread
If you call Thread.Sleep, it's probably wrong
Your questions demonstrate an opportunity for you to learn new architectural patterns. These look like good candidates;
http://www.codeproject.com/Articles/99143/BackgroundWorker-Class-Sample-for-Beginners
http://www.codeproject.com/Articles/26148/Beginners-Guide-to-Threading-in-NET-Part-1-of-n