Convert Ping application to multithreaded version to increase speed - C# - c#

I have an application that pings every possible IP on your local subnet in order to compile a list of responsive IP addresses. Currently it pings all 255 one at a time. Is it possible to convert this app to use multiple threads to increase the speed by pinging more than one at a time? I am new to the concept of multiple threads and figure this would be a good way to learn(as long as it's possible of course).
also, any stylistic improvements you can educate me on would also be helpful.
thanks ahead of time
Here is the current pinging method in a backgroundWorker1_DoWork event.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
count = 0;
for (int i = 1; i < 255; i++)
{
Ping ping = new Ping();
PingReply pingreply = ping.Send(IPAddress.Parse(locip[0] + "." + locip[1] + "." + locip[2] + "." + i));
count += 1;
if (pingreply.Status == IPStatus.Success)
{
status = "o";
repAddress = pingreply.Address.ToString(); ;
repRoundtrip = pingreply.RoundtripTime.ToString();
repTTL = pingreply.Options.Ttl.ToString();
repBuffer = pingreply.Buffer.Length.ToString();
string[] lineBuffer = { status, repAddress, repRoundtrip, repTTL, repBuffer };
ipList.Rows.Add(lineBuffer);
}
progressBar.Invoke(new MethodInvoker(UpdateProgressBarByOne));
progressStatus.Text = ("Pinging IP " + count + " of 254");
}
button1.Enabled = true;
progressBar.Invoke(new MethodInvoker(ResetProgressBar));
}

It looks like Ping has a SendAsync function. This post (I know its vb, but just to get an idea) has an example. In summary, just change your Send to SendAsync and listen for the PingCompleted event

Well my advice is to look into your concurrency points.
Firstly you will hit a bug with any access to windows forms objects off the thread. i.e your access to button1 WILL throw an MDA in debug, and might crash at runtime randomly. You have to use a delegate and invoke the method back on the main thread using a pattern like this.
this.Invoke(delgatetomyupdatermethod)
Secondly, your time is spent in the ping itself. So I would recommend writing a threadsafe list (just write a method with a lock on it
private object locker = new object();
private void InsertIntoList(string linebuffer)
{
lock(locker)
{
ipList.Rows.Add(linebuffer);
}
}
I would recommend using the .Net threadpool to run your method instead to ping a given IP.
To do this write a function that will take in the IP to ping and to update the list with your result, then call it by queueing up items on the threadpool. Indeed if you pass in an object with a ManualResetEvent you can even write your code to say
System.Threading.WaitHandle[] waits = new System.Threading.WaitHandle[255];
//initialise the list of these and create the objects to ping.
foreach (var obj in mylistofobjectvalues)
{
System.Threading.Threadpool.QueueUserWorkItem(method, obj);
}
System.Threading.WaitHandle.WaitAll(waits);
where method is the ping method, obj contains an object with the manualresetevent and information your method needs to ping it's target.
Each time your waithandle completes you can update your state. With some more effort on your GUI you could even have the system working asynchronously, so that your gui is updated on each response, not just at the end.

Related

DateTime multithreading UDP Sender has very different time results when re-assigning the value of DateTime object in my schedule loop

Summary: the only code difference between blocks is the assignment and re-assignment of the DateTime object
I have an app that sends UDP packets out on a very redamentry "schedule". I am seeing some behavior that makes me think I have a big misunderstanding about timers, threads, or some other concepts- I am trying to send out packets using the SendAllMessages() method based on a SendingSchedule List. My sending freqencies are are 12.5Hz, or just under a .1 seconds delay between each burst of messages. However, I am seeing much different values if I re-assign DateTime object within my loop in this method. Note that this method is run in 4 different tasks, so 4 different threads. The first example of my code gives the behavior I desire and expect: sending 4 packets sent at nearly the same time, then .08 seconds later I see another burst of 4 messages. The second example of code shows messages at a much slower rate, but I don't understand why. I thought both would behave identically. Is my "time" object being shared between threads somehow in my second example, or is something else happening?
WorkingCode (burst of 4 messages followed by waiting .08 seconds before another burst):
private static void SendAllMessages(List<DataMessageFormat> dataMessageList, UDPSender udpSender, byte[] first4bytes, int messageSize, bool loopContinuously = false)
{
// pass inetMessageList to DataMessageEncoder
MessageDataEncoder dataMessageEncoder = new MessageDataEncoder();
List<byte[]> byteArrayListDataMessage = dataMessageEncoder.ConvertFromFormatToByteArray(dataMessageList, first4bytes, messageSize, switchDefaultEndian);
Console.WriteLine("Sending " + first4bytes + " UDP Messages on Thread" + Thread.CurrentThread.ManagedThreadId);
do
{
DateTime start = DateTime.Now;
for (int i = 0; i < byteArrayListDataMessage.Count; i++) // all message lists must have the same count for this to work
{
DateTime time = start.AddSeconds(dataMessageEncoder.SendingSchedule[i]);
Send:
if (DateTime.Now > time)
{
udpSender.SendUDPOnce(byteArrayListDataMessage[i]);
}
else
{
System.Threading.Thread.Sleep(1);
goto Send;
}
}
} while (loopContinuously);
}
The below code waits a very long time between bursting 4 messages, almost like the threads are all waiting on the same DateTimeObject:
private static void SendAllMessages(List<DataMessageFormat> dataMessageList, UDPSender udpSender, byte[] first4bytes, int messageSize, bool loopContinuously = false)
{
// pass inetMessageList to DataMessageEncoder
MessageDataEncoder dataMessageEncoder = new MessageDataEncoder();
List<byte[]> byteArrayListDataMessage = dataMessageEncoder.ConvertFromFormatToByteArray(dataMessageList, first4bytes, messageSize, switchDefaultEndian);
Console.WriteLine("Sending " + first4bytes + " UDP Messages on Thread" + Thread.CurrentThread.ManagedThreadId);
do
{
DateTime time = DateTime.Now;
for (int i = 0; i < byteArrayListDataMessage.Count; i++) // all message lists must have the same count for this to work
{
time = time.AddSeconds(dataMessageEncoder.SendingSchedule[i]);
Send:
if (DateTime.Now > time)
{
udpSender.SendUDPOnce(byteArrayListDataMessage[i]);
}
else
{
System.Threading.Thread.Sleep(1);
goto Send;
}
}
} while (loopContinuously);
}
Below is my good code resulting screenshot of wireshark
Below is my Bad code resulting screenshot of wireshark
Just to give you an idea of what this app is doing:
Both codes have different logic:
First: the time value you are comparing is the initial time plus the schedule. Once you hit the desired time, probably the if test will always be true and you send the entire byteArrayListDataMessage.Count elements.
Second: every step of the for loop creates moving target so only one element gets sent.

Can I use Ping.SendAsync to determine if I haven't been able to get a reply from an IP address for a long time?

I have an application which contains a listview that has a list of IP address, i'm using Ping.SendAsync to ping the addresses.
private void timer1_Tick(object sender, EventArgs e)
{
foreach (ListViewItem lvitem in listView1.Items)
{
string input = lvitem.Text; ;
string ip = input ;
Ping pingSender = new Ping();
pingSender.PingCompleted += new PingCompletedEventHandler(ping_PingCompleted);
pingSender.SendAsync(ip, 1000, lvitem);
((IDisposable)pingSender).Dispose();
}
}
private static void ping_PingCompleted(object sender, PingCompletedEventArgs e)
{
ListViewItem lvitem = e.UserState as ListViewItem;
if (e.Reply.Status == IPStatus.Success)
{
lvitem.ImageIndex = 0; //a "check" image
}
else
{
lvitem.ImageIndex = 1; //a "X" image
}
GC.Collect();
}
I have 2 results right now, if it's a success or if it's something else. Timed out requests are common on some of the IP address but they'll return a reply most of the time, I want to display a different image if I haven't gotten a success reply from an ip address for a long time, how can I do this?
You can check for equality with IPStatus.TimedOut:
The ICMP echo Reply was not received within the allotted time. The default time allowed for replies is 5 seconds. You can change this value using the Send or SendAsync methods that take a timeout parameter.
Your current implementation has a 1 second timeout, which means that any PingReply object which passes that specified time should be flagged as timed out.
Side Note:
For some reason you're disposing the Ping class while the asynchronous operation is executing, i'm not really sure how that code actually works for you, but you should only dispose once you're actually done with the operation after the results are retrieved. Actually, i'd leave it up to the GC to figure that out on its own.
Also, calling GC.Collect should happen pretty rarely. See this question for more guidelines.

Timing control in C# Socket Programming

I'm currently getting started on a socket programming project for a University network planning course. I'm also doing a Programming class in which we are learning C# so I thought it appropriate to use C# to complete this assignment.
The assignment is to create a simple Server-Client connection and have data sent between them. That is not too much of a problem, I've read a few tutorials and watched a few videos and I think I know what I'm doing. That part which has me a little confused is this:
"2) Every second, the server sends Client a command to seek measurement data, e.g., through a single letter "R" or "r" (request). (timing control is required here)."
This has me confused, What exactly is timing control? And how can I go about implementing it.
Thanks in advance.
EDIT: I found an "example" of timing control, but it is in the C/C++, Do I need to do something liek this?
/* Step 5.2: Send and Receive Data in loops */
time_old = getTime();
iterationStep = 1;
for (;;)
{
recvStatus = recv(TCPClient, recvBuffer,128,0);
if(recvStatus == 0)
break;
else if(recvStatus == SOCKET_ERROR)
{
printf("Failed in recv(): %d\n",WSAGetLastError());
break;
}
recvBuffer[recvStatus] = 0x00; /* '\0' */
time_new = getTime();
time_interval = time_new - time_old;
time_old = time_new;
printf("Step = %5d; Time Interval = %8.6f; Received String: %s\n", iterationStep,time_interval,recvBuffer);
iterationStep++;
}
/* if "EXIT" received, terminate the program */
if (!strcmp(recvBuffer,"EXIT"))
{
printf("TCP Server ready to terminate.");
break;
}
}
EDIT 2:
Im trying now to use this method but am having some trouble. I have created this method:
private static void SendRequest(Object source, ElapsedEventArgs e) {
byte[] buffer = Encoding.Default.GetBytes("WAAAAT");
acc.Send(buffer, 0, buffer.Length, 0);
}
But as you can see, I cannot use the "acc" socket because I can set it as a parameter. I tried to but then I get a lot of errors when calling the method, any advice?
It sounds like you will need to use the "System.Timers.Timer" class to execute your "send request" function every second.
Example:
static void Main()
{
// Create a timer with a one second interval.
aTimer = new System.Timers.Timer(1000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += SendRequest;
aTimer.Enabled = true;
}
private static void SendRequest(Object source, ElapsedEventArgs e)
{
// maybe end existing request if not completed?
// send next request
}
Whether you time out(cancel) any existing requests before starting a new one will depend on your requirements as it is also possible to have many requests running in parallel. If you do need to kill a request, you can do so by disposing the System.Net.Sockets.Socket that initiated the connection attempt (you will need to handle any errors thrown by the Socket.Connect).
Timing control sounds like a mechanism to insure that the requests are fired 1 sec apart and that if a request doesn't complete in a timely fashion to terminate that request and fire the next one.
Take a scenario
Request 1 fires at point 0
After 1 sec request 1 hasn't received an answer but request 2 needs to fire.
You probably need to implement a timeout system based on a clock.

communicating with multiple slave (Modbus protocol based)

I am developing an application in which Lets says 50-60 Modbus supporting devices (Slaves) are connected to a Com Port which are communicating with my application in request response mechanism.
I want after every 15 min. request should be sent to every meter and response to be received from meter one by one.
communicating with multiple slave (Modbus protocol based)
For this i am making the use of System.Timers.timer to call the method lets say ReadAllSlave() after every 15 min.
In ReadAllSlave() i have used For loop to send the request and to receive response and using thread.sleep to maintain the delay..! but it seems that its not working and loop is executing in damn wired way.
private void StartPoll()
{
double txtSampleRate = 15 * 60 * 1000;
timer.Interval = txtSampleRate;
timer.AutoReset = true;
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
for(int index = 0; index<meterCount; Index++)
{
//Sending request to connected meter..
mb.SendFc3(m_slaveID[0], m_startRegAdd[0], m_noOfReg[0], ref value_meter);
if (mb.modbusStatus == "Read successful")
{
//Some code for writing the values in SQL Express database
}
//Wait for some time so that will not get timeout error for the next
//request..
Thread.Sleep(10000);
}
}
Can any one please suggest me the best approach to implement the same.
Thanks in advance.
It looks like your problem is a trivial one... You're always interrogating the same slave !
"index" is never used in your code...
What about something like this :
mb.SendFc3(m_slaveID[index], m_startRegAdd[index], m_noOfReg[index], ref value_meter);

C# server - is this good way for timeouting and disconnecting?

On my multithreaded server I am experiencincg troubles with connections that are not coming from the proper Client and so hang unathorized. I did not want to create new thread only for checking if clients are connected for some time without authorization. Instead of this, I have add this checking to RecieveData thread, shown on the code below. Do you see some performance issue or this is acceptable? The main point is that everytime client is connected (and Class client is instantionized) it starts stopwatch. And so I add to this thread condition - if the time is greater than 1 and the client is still not authorized, its added on the list of clients determinated for disconnection. Thanks
EDIT: This While(true) is RecieveData thread. I am using async. operations - from tcplistener.BeginAccept to threadpooling. I have updated the code to let you see more.
protected void ReceiveData()
{
List<Client> ClientsToDisconnect = new List<Client>();
List<System.Net.Sockets.Socket> sockets = new List<System.Net.Sockets.Socket>();
bool noClients = false;
while (true)
{
sockets.Clear();
this.mClientsSynchronization.TryEnterReadLock(-1);
try
{
for (int i = 0; i < this.mClientsValues.Count; i++)
{
Client c = this.mClientsValues[i];
if (!c.IsDisconnected && !c.ReadingInProgress)
{
sockets.Add(c.Socket);
}
//clients connected more than 1 second without recieved name are suspect and should be disconnected
if (c.State == ClientState.NameNotReceived && c.watch.Elapsed.TotalSeconds > 1)
ClientsToDisconnect.Add(c);
}
if (sockets.Count == 0)
{
continue;
}
}
finally
{
this.mClientsSynchronization.ExitReadLock();
}
try
{
System.Net.Sockets.Socket.Select(sockets, null, null, RECEIVE_DATA_TIMEOUT);
foreach (System.Net.Sockets.Socket s in sockets)
{
Client c = this.mClients[s];
if (!c.SetReadingInProgress())
{
System.Threading.ThreadPool.QueueUserWorkItem(c.ReadData);
}
}
//remove clients in ClientsToDisconnect
foreach (Client c in ClientsToDisconnect)
{
this.RemoveClient(c,true);
}
}
catch (Exception e)
{
//this.OnExceptionCaught(this, new ExceptionCaughtEventArgs(e, "Exception when reading data."));
}
}
}
I think I see what you are trying to do and I think a better way would be to store new connections in a holding area until they have properly connected.
I'm not positive but it looks like your code could drop a valid connection. If a new connection is made after the checking section and the second section takes more than a second all the timers would time out before you could verify the connections. This would put the new connections in both the socket pool AND the ClientsToDisconnect pool. Not good. You would drop a currently active connection and chaos would ensue.
To avoid this, I would make the verification of a connection a seperate thread from the using of the connection. That way you won't get bogged down in timing issues (well...you still will but that is what happens when we work with threads and sockets) and you are sure that all the sockets you are using won't get closed by you.
My gut reaction is that while (true) plus if (sockets.Count == 0) continue will lead to heartache for your CPU. Why don't you put this on a Timer or something so that this function is only called every ~.5s? Is the 1s barrier really that important?

Categories

Resources