Error when trying to use Ping in Unity - C# - c#

I am trying to ping one of my servers using C# Ping to see whether it is available or not, but I am receiving a weird error and I'm not sure what's causing it
On first execution of the code, it returns an error but states that the operation was completed successfully
System.Net.Sockets.SocketException (0x80004005): The operation completed successfully.\r\n\r\n at System.Net.Sockets.Socket..ctor (System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType) [0x00069]
Each time the code is executed after the first, it will return a different error.
"An attempt was made to access a socket in a way forbidden by its access permissions."
System.Net.Sockets.SocketException (0x80004005)
The code I am using to ping is as follows which is pretty much pulled straight from MSDN. https://msdn.microsoft.com/en-us/library/system.net.networkinformation.pingreply(v=vs.110).aspx
public static bool pingHost(string nameOrAddress)
{
bool pingable = false;
if (nameOrAddress == "127.0.0.1")
{
return true;
}
try
{
System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 3;//3 seconds?
PingReply reply = pingSender.Send(nameOrAddress, timeout);
if (reply.Status == IPStatus.Success)
{
pingable = true;
} else
{
pingable = false;
}
}
catch (PingException e)
{
Debug.Log("Error pinging: " + e.Message + " - " + e.StackTrace);
// Discard PingExceptions and return false;
}
return pingable;
}
I am able to ping the server from my terminal on my machine, but not through code. Why am I receiving this error?
EDIT
I have tested the code in a standard C# application and it works fine. This issue must be something related to Unity.
Unity has its own Ping class but can't be called from outside the main thread. The code below tries to utilise this, but it always returns false and -1 for the time.
Ping should definitely complete within 3 seconds? I have tried increasing this time to 10 seconds but still returns false. The address is definitely pingable as I can ping it from the terminal.
IEnumerator ping()
{
while (true)
{
UnityEngine.Ping pinger = new UnityEngine.Ping("ADDRESS");
yield return new WaitForSeconds(3.0f);
Debug.Log("Ping finished? " + pinger.isDone + " - " + pinger.time);
yield return new WaitForSeconds(2.0f);
}
}
As this doesn't work, my next question is how does the Unity ping actually work? My servers are in a secure environment with only specific open ports. If it is doing something unexpected other than the standard ping, it may not be able to.
EDIT 2
IEnumerator ping()
{
while (true)
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
PingFinished(p);
}
}
This code seems to work nicely, but only works from the main thread. I will need a solution that is able to be started from a separate task or thread.

This seems to work, but only from the main thread.
IEnumerator ping()
{
while (true)
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
PingFinished(p);
}
}

Here's a general idea of how to do it on/off the main thread:
(Caution: untested)
using System.Threading;
class Test : MonoBehaviour {
Ping result;
private object pingLock;
void Start() {
pingLock = new object();
new Thread(ThingRunningOffMainThread).Start();
StartCoroutine(DoPing());
}
IEnumerator DoPing()
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
Monitor.Enter(pingLock);
result = p;
Monitor.Pulse(pingLock);
Monitor.Exit(pingLock);
}
void ThingRunningOffMainThread() {
if (result == null) {
Monitor.Enter(pingLock);
while (result == null) {
Monitor.Wait(pingLock);
}
Monitor.Exit(pingLock);
}
PingFinished(pingLock);
}
}
To invoke from a background thread to the main thread, look at Main Thread Dispatchers, for example:
https://github.com/PimDeWitte/UnityMainThreadDispatcher/blob/master/UnityMainThreadDispatcher.cs

Related

using ping in infinite loop

I want to check the instrument connectivity, continuously. These instruments are connected by LAN.
I ping them in an infinite loop. After a few seconds, I'm met with a blue screen and the system restarts.
private async void checkingDevice()
{
await Task.Run(() =>
{
do
{
Panel selectedPanel;
multicastPing.send();
foreach (var device in (Device[])Enum.GetValues(typeof(Device)))
{
selectedPanel = (Panel)this.Controls.Find((device).ToString(), true)[0];
if (multicastPing.check(device.ToString()))
selectedPanel.BackgroundImage = Image.FromFile(Configs.imagesUrl + "enable\\" + selectedPanel.AccessibleName + ".png");
else
selectedPanel.BackgroundImage = Image.FromFile(Configs.imagesUrl + "disable\\" + selectedPanel.AccessibleName + ".png");
}
} while (!flag);
// TODO
// delete instrument object after using in this snippet code
});
}
public bool send()
{
foreach (var device in (Device[])Enum.GetValues(typeof(Device)))
replyDictionary[device.ToString()] = sendDictionary[device.ToString()].Send(Configs.instrumentSpecification[device.ToString()].ip).Status;
return true;
}
My career was in Test and Measurement and doing this kind of thing seems quite familiar. So I'm offering this as one approach to see if I can assist you in pinging your instrument stack.
Getting a blue screen is pretty rare and just from personal experience it's likely that a very low-level IO kernel driver (ethernet port?) is having a bad time of something. Potentially, it appears that the loop could run very fast to the point of overrunning a buffer perhaps? Or, pathologically, you may inadvertently be binding the UI thread to that of a kernel driver one. Ouch.
I agree with comments about safely calling the UI thread from a task using MethodInvoker. But I think perhaps the main issue might be coming from the fact that this loop "runs as fast as it can" which might be pretty fast. I modeled something like this that throttles the pings so that they occur some limited number of times per second and it seems to work fine.
A safely-threaded task that performs the look without ever blocking on the UI thread looks something like this:
CancellationTokenSource _cts = null;
SemaphoreSlim ssBusy = new SemaphoreSlim(1);
private void ExecMulticastPing()
{
ssBusy.Wait();
Task.Run(() =>
{
try
{
_cts = new CancellationTokenSource();
do
{
List<Task<PingReply>> asyncPings = new List<Task<PingReply>>();
// Sends out the pings in rapid succession to execute asynchronously in parallel
foreach (var device in (Device[])Enum.GetValues(typeof(Device)))
{
asyncPings.Add(Task.Run(() => SinglePingAsync(device, _cts.Token)));
}
// Waits for all the async pings to complete.
Task.WaitAll(asyncPings.ToArray());
// See if flag is already cancelled
if (_cts.IsCancellationRequested) break;
foreach (var device in (Device[])Enum.GetValues(typeof(Device)))
{
SetPanelImage(device, asyncPings[(int)device].Result);
}
// I believe that it's very important to throttle this to
// a reasonable number of repeats per second.
Task.Delay(1000).Wait();
BeginInvoke((MethodInvoker)delegate
{
WriteLine(); // Newline
});
} while (!_cts.IsCancellationRequested); // Check if it's cancelled now
}
finally
{
ssBusy.Release();
}
BeginInvoke((MethodInvoker)delegate
{
WriteLine("CANCELLED");
});
});
}
... where ...
const string URL_FOR_TEST = #"www.ivsoftware.com";
private PingReply SinglePingAsync(Device device, CancellationToken token)
{
if(token.IsCancellationRequested)
{
return null;
}
Ping pingSender = new Ping();
PingOptions options = new PingOptions()
{
DontFragment = true
};
PingReply reply = pingSender.Send(URL_FOR_TEST);
BeginInvoke((MethodInvoker)delegate
{
if (reply.Status == IPStatus.Success)
{
WriteLine("Address: " + reply.Address.ToString());
WriteLine("RoundTrip time: " + reply.RoundtripTime);
WriteLine("Time to live: " + reply.Options.Ttl);
WriteLine("Don't fragment: " + reply.Options.DontFragment);
WriteLine("Buffer size: " + reply.Buffer.Length);
WriteLine();
}
else
{
WriteLine("REQUEST TIMEOUT");
}
});
return reply;
}
... and ...
private void SetPanelImage(Device device, PingReply reply)
{
BeginInvoke((MethodInvoker)delegate
{
WriteLine("Setting panel image for " + device.ToString() + " " + reply.Status.ToString() );
Panel selectedPanel = (
from Control unk in Controls
where
(unk is Panel) &&
(unk.Name == device.ToString()) // ... or however you go about finding the panel...
select unk as Panel
).FirstOrDefault();
if (selectedPanel != null)
{
switch (reply.Status)
{
case IPStatus.Success:
// Set image for enabled
break;
case IPStatus.TimedOut:
// Set image as disabled
break;
default:
// Set image as disabled
break;
}
}
});
}
This 10-second screen capture demonstrates the success of this approach and you can browse the complete example code on our GitHub repo if you think this would be helpful. I also answered a different-but-related question here.

Why is the Windows Forms UI blocked when executing Task with ContinueWith?

I spent a couple of days searching in Google and trying to understand why in my case Windows Forms UI is blocked when executing pings in Tasks.
I saw a lot of similar cases, but none of them explains my specific case.
Issue description:
I have an application which sends pings asynchronously. Each ping is send inside of a Task. I use .ContinueWith to receive result of a ping and print it to textbox without blocking UI thread. It works OK if I launch all pings once. If I add a while {run} loop to make them run forever my UI becomes unresponsive and blocked, and none of the results are printed to the textbox.
Problematic Code:
Action action2 = () => {
for (int i = 0; i < ipquantity; i++)
{
int temp1 = i;
string ip = listView1.Items[temp1].SubItems[1].Text;
if (finished[temp1] == true) // Variable helps to check if ping reply was received and printed
continutask[temp1] = Task<string>.Run(() => PingStart(ip, temp1)).ContinueWith(antecedent => PrintResult(antecedent.Result, temp1));
}
};
while (run)
{
action2();
Thread.Sleep(1000);
}
Questions:
Why is the UI blocked with a while loop and why is it not blocked without it?
How can I modify my code to be still able to use Tasks for pings without blocking the UI?
Is there a better way to launch endless pings to several IP addresses simultaneously?
Complete code:
private async void buttonStart_Click(object sender, EventArgs e)
{
run = true;
int count = listView1.Items.Count;
task = new Task<string>[count];
result1 = new string[count];
finished = new bool[count];
continutask = new Task[count];
for (int i = 0; i < count; i++)
{
finished[i] = true;
}
Action action2 = () =>
{
for (int i = 0; i < count; i++)
{
int temp1 = i;
string ip = listView1.Items[temp1].SubItems[1].Text;
if (finished[temp1] == true)
continutask[temp1] = Task<string>.Run(() => PingStart(ip, temp1)).ContinueWith(antecedent => PrintResult(antecedent.Result, temp1));
}
};
while (run)
{
action2();
//await Task.Delay;
//Thread.Sleep(1000);
}
}
public void PrintResult(string message, int seqnum)
{
Action action = () =>
{
textBox1.AppendText(message);
textBox1.AppendText(Environment.NewLine);
textBox1.AppendText("");
textBox1.AppendText(Environment.NewLine);
};
if (InvokeRequired)
Invoke(action);
else
action();
finished[seqnum] = true;
}
public string PingStart(string ip, int seqnum)
{
finished[seqnum] = false;
Ping isPing = new Ping();
PingReply reply;
const int timeout = 2000;
const string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
options.DontFragment = false;
reply = isPing.Send(ip, timeout, buffer, options);
string rtt = (reply.RoundtripTime.ToString());
string success = "N/A";
if (reply.Status == IPStatus.Success)
{
success = $"{ip}" + " Success!" + $" rtt: [{rtt}]" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
else if (reply.Status != IPStatus.Success)
{
success = $"{ip}" + $" Not Successful! Status: {reply.Status}" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
return success;
}
Since you already create (and save) your tasks, the easiest fix would be to await them for each iteration of your while loop:
while (run)
{
action2();
foreach (Task t in continutask)
await t;
}
That way, when all pings completed (successful or not) you start the entire process again - without delay.
One more thing: You could add a textBox1.ScrollToEnd(); to PrintResult
Since there is a lot of room for improvement, below is a rewritten and simplified example. I've removed a lot of unused variables (e.g. seqnum) and made the PingStart method completely asynchronous. I also replaced your ListBox with a TextBox for easier testing, so you might want to revert that in your code.
This still isn't the cleanest of all possible implementations (mainly because of the global run) but it should show you how to do things "more async" :)
private async void buttonStart_Click(object sender, EventArgs e)
{
// If the ping loops are already running, don't start them again
if (run)
return;
run = true;
// Get all IPs (in my case from a TextBox instead of a ListBox
string[] ips = txtIPs.Text.Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
// Create an array to store all Tasks
Task[] pingTasks = new Task[ips.Length];
// Loop through all IPs
for(int i = 0; i < ips.Length; i++)
{
string ip = ips[i];
// Launch and store a task for each IP
pingTasks[i] = Task.Run(async () =>
{
// while run is true, ping over and over again
while (run)
{
// Ping IP and wait for result (instead of storing it an a global array)
var result = await PingStart(ip);
// Print the result (here I removed seqnum)
PrintResult(result.Item2);
// This line is optional.
// If you want to blast pings without delay,
// you can remove it
await Task.Delay(1000);
}
}
);
}
// Wait for all loops to end after setting run = false.
// You could add a mechanism to call isPing.SendAsyncCancel() instead of waiting after setting run = false
foreach (Task pingTask in pingTasks)
await pingTask;
}
// (very) simplified explanation of changes:
// async = this method is async (and therefore awaitable)
// Task<> = This async method returns a result of type ...
// Tuple<bool, string> = A generic combination of a bool and a string
// (-)int seqnum = wasn't used so I removed it
private async Task<Tuple<bool, string>> PingStart(string ip)
{
Ping isPing = new Ping();
const int timeout = 2000;
const string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions {DontFragment = false};
// await SendPingAsync = Ping and wait without blocking
PingReply reply = await isPing.SendPingAsync(ip, timeout, buffer, options);
string rtt = reply.RoundtripTime.ToString();
bool success = reply.Status == IPStatus.Success;
string text;
if (success)
{
text = $"{ip}" + " Success!" + $" rtt: [{rtt}]" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
else
{
text = $"{ip}" + $" Not Successful! Status: {reply.Status}" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
// return if the ping was successful and the status message
return new Tuple<bool, string>(success, text);
}
This way you will have a loop for each IP that will continue independently of each other until run is set to false.
Thread.Sleep(n) blocks the current thread for n milliseconds. If I understand the code correctly it executes action2 then suspends the calling thread for one second. If that thread is the main (UI) thread, your UI will be blocked.
Maybe moving the while loop to yet another thread would fix the problem.

Using Threads in a C# function for Excel

I am writing a ping function for Excel. This function suppose to take a column of IP address (about 200 address) and ping each one of them.
To avoid Excel getting stuck, I have decided to use a thread that will send the pings instead of the main thread. The problem is that the thread can't access the cell values and the Excel crashes.
I hope that someone could help me with this.
Here is the code :
private LinkedList<string> Iplist;
private Thread t;
public NetworkPing()
{
}
public int CalcPingColumn(Range IPcells, Range ANScells)
{
CreateIpList(IPcells);
this.t = new Thread(() => CalcPing_method(ANScells));
this.t.Start();
return 1;
}
//THE PROBLEM IS PREOBBLY HERE
private void CalcPing_method(Range ANScells)
{
foreach (Range ans in ANScells.Cells)
{
ans.Value2 = Ping(Iplist.Last.Value);
Iplist.RemoveLast();
Thread.Sleep(50);
}
}
private void CreateIpList(Range IPcells)
{
Iplist = new LinkedList<string>();
foreach (Range ip in IPcells.Cells)
{
Iplist.AddFirst(ip.Value2);
}
}
Try to use the BackgroundWorker-class instead of the regular Thread. It makes it more easy to "send" objects/instances between threads. From that you can also get progress: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx
why not one function?
public string PingIpadress(string ipadress)
{
var pingSender = new Ping();
var options = new PingOptions();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
PingReply reply = pingSender.Send(ipadress, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
return "alive " + reply.Options.Ttl;
}
return "no response";
}

Unable to connect to other instances of the same program via TCP

I know this might have been asked a thousand times before, but I can't seem to find any specific information about my case.
I have a C# client program that has to connect to other instances of the client over a LAN. To connect one client to another, I use a TcpListener/TcpClient aproach. Both instances have a listener and are able to create a new client to connect/listen to one another (it is independant of which instance started the connection).
To create the listener, I use the following bit of code:
// In the constructor:
listener = new TcpListener(IPAddress.Any, 32842);
listenThread = new Thread((ThreadStart)ListenForConnections);
listenThread.Name = "ListenThread";
listenThread.IsBackground = true;
listenThread.Start();
// Listening for connections:
private void ListenForConnections()
{
listener.Start();
Console.WriteLine("Started listening for connections");
for (; ; )
{
if (listener.Pending())
{
using (TcpClient client = listener.AcceptTcpClient())
{
// My own layer over the TcpClient.
AsyncTCPClient other = new AsyncTCPClient(client);
Console.WriteLine("Connection from " + client.Client.RemoteEndPoint);
other.Received += DataReceived;
other.Exception += ExceptionOccurred;
connections.Add("Player", other);
other.Start();
}
}
else
{
Thread.Sleep(5);
}
}
}
To create and connect to another client, I use the following bit of code:
public void Connect(IPEndPoint other)
{
if (socket == null)
{
socket = new TcpClient(AddressFamily.InterNetwork);
socket.Client.ReceiveBufferSize = 2 * 1024 * 1024;
}
// Should force-close the socket after 5 seconds if it can't be closed automatically.
socket.LingerState = new LingerOption(true, 5);
socket.BeginConnect(other.Address, other.Port, ConnectionCallback, other);
IsConnecting = true;
}
The ConnectionCallback given as a parameter to BeginConnect looks like this:
private void ConnectionCallback(IAsyncResult result)
{
IsConnecting = false;
IsConnected = socket.Connected;
if (IsConnected)
{
IPEndPoint connectedTo = (IPEndPoint)result.AsyncState;
stream = socket.GetStream();
if (Connected != null)
{
Connected(this, null);
}
}
else
{
if (Exception != null)
{
RaiseException(new Exception("Unable to connect to host"));
}
}
}
However, everytime I get to the callback, the TcpClient failed to connect to the other instance and the Exception event is thrown. Now what I've found while searching around the internet (Google) is that it might have something to do with a firewall on either sides of the connection. But I've tested it with all firewalls off, so this can't be that.
I don't see Socket.EndConnect() being called in the callback.
See this in MSDN:
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.endconnect.aspx

The fastest way to ping a large list of IP adresses?

I have a large list of IP addresses in a datatable and i have to ping them so quickly,
I used this code :
public bool PingIP(string IP)
{
bool result = false;
try
{
Ping ping = new Ping();
PingReply pingReply = ping.Send(IP);
if (pingReply.Status == IPStatus.Success)
result = true;
}
catch
{
result = false;
}
return result;
}
then i call it in while loop :
private void CheckNetworkState()
{
while (rowindexping > -1)
{
if (rowindexping == tbl_ClientInfo.Rows.Count)
{
rowindexping = -1;
return;
}
string ip = tbl_ClientInfo.Rows[rowindexping]["clientip"].ToString();
if (!PingIP(ip))
{
do something
}
rowindexping++;
Thread.Sleep(100);
}
}
Since i want to do this work at the background of my project i call the class in a thread:
threadping = new Thread(CheckNetworkState);
threadping.IsBackground = true;
threadping.Start();
my problem is that it takes so many time and does not work at the background. i mean the system is busy till all ip addresses in tbl_clientinfo go through the ping class.
i want that system check all rows since i'm working with other part of my project.
Did i do correctly?
Your code is running all the code on a single thread; you're not using multiple threads. Also, why do you have a Thread.Sleep in there?
Try the following:
Query the database and get all the IPs
In a loop, spin up a new thread that will run PingIP for each IP address
Note: You can also spin up a new thread every time you get a new row from the database
Sample:
static void Main(string[] args)
{
// get the IPs from the database so you can iterate over them
List<string> ips = new List<string>()
{
"google.com",
"127.0.0.1",
"stackoverflow.com"
};
foreach (var ip in ips)
{
// See http://stackoverflow.com/questions/4744630/unexpected-behaviour-for-threadpool-queueuserworkitem
// for reason to use another variable in the loop
string loopIp = ip;
WaitCallback func = delegate(object state)
{
if (PingIP(loopIp))
{
Console.WriteLine("Ping Success");
}
else
{
Console.WriteLine("Ping Failed");
}
};
ThreadPool.QueueUserWorkItem(func);
}
Console.ReadLine();
}
public static bool PingIP(string IP)
{
bool result = false;
try
{
Ping ping = new Ping();
PingReply pingReply = ping.Send(IP);
if (pingReply.Status == IPStatus.Success)
result = true;
}
catch
{
result = false;
}
return result;
}
What I would do is have a separate multi-threaded daemon running in the background, doing the pings, and putting the results in a database. Have a page that loads results via AJAX later.
Consider making a system call to the fping utility. Granted, it's not managed code, but fping is very well optimized for your specific task and would simplify your problem down to a single call followed by the processing of a text-based list of results.
you can use powershell
private string resultat(string s)
{
Runspace space = RunspaceFactory.CreateRunspace();
space.Open();
Pipeline pipeline = space.CreatePipeline();
pipeline.Commands.AddScript(s);
pipeline.Commands.Add("Out-String");
Collection<PSObject> results = pipeline.Invoke();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
}
and then use resultat("ping -l 10 -n 2 " + your_ip);

Categories