Does anyone have C# code handy for doing a ping and traceroute to a target computer? I am looking for a pure code solution, not what I'm doing now, which is invoking the ping.exe and tracert.exe program and parsing the output. I would like something more robust.
Given that I had to write a TraceRoute class today I figured I might as well share the source code.
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Text;
using System.Net;
namespace Answer
{
public class TraceRoute
{
private const string Data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
public static IEnumerable<IPAddress> GetTraceRoute(string hostNameOrAddress)
{
return GetTraceRoute(hostNameOrAddress, 1);
}
private static IEnumerable<IPAddress> GetTraceRoute(string hostNameOrAddress, int ttl)
{
Ping pinger = new Ping();
PingOptions pingerOptions = new PingOptions(ttl, true);
int timeout = 10000;
byte[] buffer = Encoding.ASCII.GetBytes(Data);
PingReply reply = default(PingReply);
reply = pinger.Send(hostNameOrAddress, timeout, buffer, pingerOptions);
List<IPAddress> result = new List<IPAddress>();
if (reply.Status == IPStatus.Success)
{
result.Add(reply.Address);
}
else if (reply.Status == IPStatus.TtlExpired || reply.Status == IPStatus.TimedOut)
{
//add the currently returned address if an address was found with this TTL
if (reply.Status == IPStatus.TtlExpired) result.Add(reply.Address);
//recurse to get the next address...
IEnumerable<IPAddress> tempResult = default(IEnumerable<IPAddress>);
tempResult = GetTraceRoute(hostNameOrAddress, ttl + 1);
result.AddRange(tempResult);
}
else
{
//failure
}
return result;
}
}
}
And a VB version for anyone that wants/needs it
Public Class TraceRoute
Private Const Data As String = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
Public Shared Function GetTraceRoute(ByVal hostNameOrAddress As String) As IEnumerable(Of IPAddress)
Return GetTraceRoute(hostNameOrAddress, 1)
End Function
Private Shared Function GetTraceRoute(ByVal hostNameOrAddress As String, ByVal ttl As Integer) As IEnumerable(Of IPAddress)
Dim pinger As Ping = New Ping
Dim pingerOptions As PingOptions = New PingOptions(ttl, True)
Dim timeout As Integer = 10000
Dim buffer() As Byte = Encoding.ASCII.GetBytes(Data)
Dim reply As PingReply
reply = pinger.Send(hostNameOrAddress, timeout, buffer, pingerOptions)
Dim result As List(Of IPAddress) = New List(Of IPAddress)
If reply.Status = IPStatus.Success Then
result.Add(reply.Address)
ElseIf reply.Status = IPStatus.TtlExpired Then
'add the currently returned address
result.Add(reply.Address)
'recurse to get the next address...
Dim tempResult As IEnumerable(Of IPAddress)
tempResult = GetTraceRoute(hostNameOrAddress, ttl + 1)
result.AddRange(tempResult)
Else
'failure
End If
Return result
End Function
End Class
This implementation is simple, lazy (properly enumerable) and it will not go on searching forever (maxTTL) like some of the other answers.
public static IEnumerable<IPAddress> GetTraceRoute(string hostname)
{
// following are similar to the defaults in the "traceroute" unix command.
const int timeout = 10000;
const int maxTTL = 30;
const int bufferSize = 32;
byte[] buffer = new byte[bufferSize];
new Random().NextBytes(buffer);
using (var pinger = new Ping())
{
for (int ttl = 1; ttl <= maxTTL; ttl++)
{
PingOptions options = new PingOptions(ttl, true);
PingReply reply = pinger.Send(hostname, timeout, buffer, options);
// we've found a route at this ttl
if (reply.Status == IPStatus.Success || reply.Status == IPStatus.TtlExpired)
yield return reply.Address;
// if we reach a status other than expired or timed out, we're done searching or there has been an error
if (reply.Status != IPStatus.TtlExpired && reply.Status != IPStatus.TimedOut)
break;
}
}
}
Although the Base Class Library includes Ping, the BCL does not include any tracert functionality.
However, a quick search reveals two open-source attempts, the first in C# the second in C++:
http://www.codeproject.com/KB/IP/tracert.aspx
http://www.codeguru.com/Cpp/I-N/network/basicnetworkoperations/article.php/c5457/
For the ping part, take a look at the Ping class on MSDN.
This is the most efficient way I could think of.
Please vote it up if you like it so others can benefit.
using System;
using System.Collections.Generic;
using System.Net.NetworkInformation;
namespace NetRouteAnalysis
{
class Program
{
static void Main(string[] args)
{
var route = TraceRoute.GetTraceRoute("8.8.8.8")
foreach (var step in route)
{
Console.WriteLine($"{step.Address,-20} {step.Status,-20} \t{step.RoundtripTime} ms");
}
}
}
public static class TraceRoute
{
public static IEnumerable<PingReply> GetTraceRoute(string hostnameOrIp)
{
// Initial variables
var limit = 1000;
var buffer = new byte[32];
var pingOpts = new PingOptions(1, true);
var ping = new Ping();
// Result holder.
PingReply result = null;
do
{
result = ping.Send(hostnameOrIp, 4000, buffer, pingOpts);
pingOpts = new PingOptions(pingOpts.Ttl + 1, pingOpts.DontFragment);
if (result.Status != IPStatus.TimedOut)
{
yield return result;
}
}
while (result.Status != IPStatus.Success && pingOpts.Ttl < limit);
}
}
}
Ping: We can use the Ping class built into the .NET Framework.
Instantiate a Ping and subscribe to the PingCompleted event:
Ping pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;
Add code to configure and action the ping, e.g.:
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
string who = "www.google.com";
AutoResetEvent waiter = new AutoResetEvent(false);
int timeout = 12000;
PingOptions options = new PingOptions(64, true);
pingSender.SendAsync(who, timeout, buffer, options, waiter);
Add a PingCompletedEventHandler:
public static void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
... Do stuff here
}
Code-dump of a full working example, based on MSDN's example:
public static void Main(string[] args)
{
string who = "www.google.com";
AutoResetEvent waiter = new AutoResetEvent(false);
Ping pingSender = new Ping();
// When the PingCompleted event is raised,
// the PingCompletedCallback method is called.
pingSender.PingCompleted += PingCompletedCallback;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
// Wait 12 seconds for a reply.
int timeout = 12000;
// Set options for transmission:
// The data can go through 64 gateways or routers
// before it is destroyed, and the data packet
// cannot be fragmented.
PingOptions options = new PingOptions(64, true);
Console.WriteLine("Time to live: {0}", options.Ttl);
Console.WriteLine("Don't fragment: {0}", options.DontFragment);
// Send the ping asynchronously.
// Use the waiter as the user token.
// When the callback completes, it can wake up this thread.
pingSender.SendAsync(who, timeout, buffer, options, waiter);
// Prevent this example application from ending.
// A real application should do something useful
// when possible.
waiter.WaitOne();
Console.WriteLine("Ping example completed.");
}
public static void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
// If the operation was canceled, display a message to the user.
if (e.Cancelled)
{
Console.WriteLine("Ping canceled.");
// Let the main thread resume.
// UserToken is the AutoResetEvent object that the main thread
// is waiting for.
((AutoResetEvent)e.UserState).Set();
}
// If an error occurred, display the exception to the user.
if (e.Error != null)
{
Console.WriteLine("Ping failed:");
Console.WriteLine(e.Error.ToString());
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
Console.WriteLine($"Roundtrip Time: {e.Reply.RoundtripTime}");
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
As am improvement to Scotts code answer above, I found that his solution doesn't work if the route tapers off into nothing before reaching the destination - it never returns. A better solution with at least a partial route could be this (which I've tested and it works well). You can change the '20' in the for loop to something bigger or smaller or try to detect if it's taking too long if you want to control the number of iterations some other way. Full credit to Scott for the original code - thanks.
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Text;
using System.Net;
...
public static void TraceRoute(string hostNameOrAddress)
{
for (int i = 1; i < 20; i++)
{
IPAddress ip = GetTraceRoute(hostNameOrAddress, i);
if(ip == null)
{
break;
}
Console.WriteLine(ip.ToString());
}
}
private static IPAddress GetTraceRoute(string hostNameOrAddress, int ttl)
{
const string Data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
Ping pinger = new Ping();
PingOptions pingerOptions = new PingOptions(ttl, true);
int timeout = 10000;
byte[] buffer = Encoding.ASCII.GetBytes(Data);
PingReply reply = default(PingReply);
reply = pinger.Send(hostNameOrAddress, timeout, buffer, pingerOptions);
List<IPAddress> result = new List<IPAddress>();
if (reply.Status == IPStatus.Success || reply.Status == IPStatus.TtlExpired)
{
return reply.Address;
}
else
{
return null;
}
}
Related
I am reading data in bytes from .bin file and split the whole byte data into 16-16 bytes frames, so I want to 16 bytes frame one by one and wait until the first frame finished its cycle.
Callback method of SerialPort class:
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Read data from serial port:
byte[] buffer = new byte[serialPort.BytesToRead];
serialPort.Read(buffer, 0, buffer.Length);
StringBuilder sb = new StringBuilder();
List<string> response = new List<string>();
for (int i = 0; i < buffer.Length; i++)
{
string currentByte = string.Format("{0:X2}", buffer[i]);
response.Add(currentByte);
sb.AppendFormat("{0:X2}", buffer[i]);
}
string responesCode = response[1].ToString();
if (responesCode == "44")
{
// Wait until the first response is not received
foreach (var packet in packetList.Skip(1))
{
// This method which sending the the data
this.ReadByteDataFromFile(packet);
}
}
}
FdBrowseFile_Click button click:
private void FdBrowseFile_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
byte[] fileBytes = File.ReadAllBytes(filename);
foreach (byte[] copySlice in fileBytes.Slices(16))
{
var splitedByteArray = copySlice;
if (splitedByteArray.Length != 16)
{
byte[] padd = new byte[16];
var startAt = 0;
Array.Copy(splitedByteArray, 0, padd, startAt, splitedByteArray.Length);
packetList.Add(padd);
}
else
{
packetList.Add(splitedByteArray);
}
}
ReadByteDataFromFile(packetList[0]);
}
}
ReadByteDataFromFile method:
public void ReadByteDataFromFile(byte[] packet) {
try {
byte[] mBuffer = new byte[24];
byte[] payload = new byte[16];
int i = 0;
foreach(var bytes in packet) {
payload[i++] = bytes;
}
CheckSumHelper checkSumHelper = new CheckSumHelper();
var ckSum = checkSumHelper.GetCheckSum(payload);
mBuffer[0] = 0x02;
mBuffer[1] = 0x10;
mBuffer[2] = CheckSumHelper.GetBytesFromDecimal(packet[0]);
mBuffer[3] = CheckSumHelper.GetBytesFromDecimal(packet[1]);
mBuffer[4] = CheckSumHelper.GetBytesFromDecimal(packet[2]);
mBuffer[5] = CheckSumHelper.GetBytesFromDecimal(packet[3]);
mBuffer[6] = CheckSumHelper.GetBytesFromDecimal(packet[4]);
mBuffer[7] = CheckSumHelper.GetBytesFromDecimal(packet[5]);
mBuffer[8] = CheckSumHelper.GetBytesFromDecimal(packet[6]);
mBuffer[9] = CheckSumHelper.GetBytesFromDecimal(packet[7]);
mBuffer[10] = CheckSumHelper.GetBytesFromDecimal(packet[8]);
mBuffer[11] = CheckSumHelper.GetBytesFromDecimal(packet[9]);
mBuffer[12] = CheckSumHelper.GetBytesFromDecimal(packet[10]);
mBuffer[13] = CheckSumHelper.GetBytesFromDecimal(packet[11]);
mBuffer[14] = CheckSumHelper.GetBytesFromDecimal(packet[12]);
mBuffer[15] = CheckSumHelper.GetBytesFromDecimal(packet[13]);
mBuffer[16] = CheckSumHelper.GetBytesFromDecimal(packet[14]);
mBuffer[17] = CheckSumHelper.GetBytesFromDecimal(packet[15]);
mBuffer[18] = 0x17;
mBuffer[19] = 0x00;
mBuffer[20] = 0x00;
mBuffer[21] = 0x00;
mBuffer[22] = Convert.ToByte(int.Parse(ckSum, System.Globalization.NumberStyles.HexNumber));
mBuffer[23] = 0x03;
serialPort.Write(mBuffer, 0, mBuffer.Length);
} catch (Exception ex) {
ExceptionHandler exceptionHandler = new ExceptionHandler();
exceptionHandler.HandleException(ex);
}
}
How I can add a delay for ReadByteDataFromFile method?
What you need is a way to block the execution of some code, until something else has happened, or - how to get things running on two threads synchronously.
.NET has quite a few classes in the System.Threading namespace for synchronization. We'll use AutoResetEvent here.
Think of AutoResetEvent as a turnstile.
You can't move forward if the the person on the other side stops.
When you move forward, you call Wait - and it blocks you from moving,
until someone calls Set on it.
Now if we apply that to our problem:
We need to stop sending data until we get an acceptable response.
So call Wait when sending data, and let the response handling code call Set to let it move forward.
Here's an example which simulates a modem.
You send some AT commands, it responds, but the responses always end with \r\n.
var port = new SerialPort("COM2");
port.Open();
var mre = new AutoResetEvent(false);
var buffer = new StringBuilder();
port.DataReceived += (s, e) =>
{
buffer.Append(port.ReadExisting());
if (buffer.ToString().IndexOf("\r\n") >= 0)
{
Console.WriteLine("Got response: {0}", buffer);
mre.Set(); //allow loop to continue
buffer.Clear();
}
};
var commandsToSend = new string[] { "AT", "AT", "AT+CSQ" };
var responseTimeout = TimeSpan.FromSeconds(10);
foreach (var command in commandsToSend)
{
try
{
Console.WriteLine("Write '{0}' to {1}", command, port.PortName);
port.WriteLine(command);
Console.WriteLine("Waiting for response...");
//this is where we block
if (!mre.WaitOne(responseTimeout))
{
Console.WriteLine("Did not receive response");
//do something
}
}
catch (TimeoutException)
{
Console.WriteLine("Write took longer than expected");
}
catch
{
Console.WriteLine("Failed to write to port");
}
}
Console.ReadLine();
Sample output when tested through virtual serial port:
(I just reply with OK<CR><LF>)
Write 'AT' to COM2
Waiting for response...
Got response: OK
Write 'AT' to COM2
Waiting for response...
Got response: OK
Write 'AT+CSQ' to COM2
Waiting for response...
Did not receive response
Wait in a loop for a full response after you write a first frame.
// Set read timeout to value recommended in the communication protocol specification
// so serial port operations don't stuck.
_port.WriteTimeout = 200;
_port.ReadTimeout = 200;
public void OnClick()
{
// Write first frame.
_port.Write(...);
// Now wait for the full response.
// Expected response length. Look for the constant value from the device communication
// protocol specification or extract from the response header (first response bytes) if
// there is any specified in the protocol.
int count = ...;
var buffer = new byte[count];
var offset = 0;
while (count > 0)
{
var readCount = _port.Read(buffer, offset, count);
offset += readCount;
count -= readCount;
}
// Now buffer contains full response or TimeoutException instance is thrown by SerialPort.
// Check response status code and write other frames.
}
In order to not block UI thread you most probably still need to utilize synchronous API and Task.Run(). See C# await event and timeout in serial port communication discussion on StackOverflow.
For more information check Top 5 SerialPort Tips article by Kim Hamilton.
I was struggling with a problem for a long time. I was using unity and I want to ping my server and router. I was using UnityPing class at the beginning and it works fine for the most of devices, but when I testing on Google Pixel(Android 7.1) it always return -1. So I tried to use System.Net.NetworkInformation to ping my server. here is my code:
private void PingToServer()
{
AutoResetEvent waiter = new AutoResetEvent(false);
System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
pingSender.PingCompleted += new PingCompletedEventHandler(PingCompletedCallback);
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 10000;
PingOptions options = new PingOptions(64, true);
IPAddress address = IPAddress.Parse("119.81.194.57");
pingSender.SendAsync(address, timeout, buffer, options, waiter);
}
private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
if (e.Cancelled)
{
Console.WriteLine("Ping canceled.");
((AutoResetEvent)e.UserState).Set();
}
if (e.Error != null)
{
Console.WriteLine("Ping failed:");
Console.WriteLine(e.Error.ToString());
((AutoResetEvent)e.UserState).Set();
}
PingReply reply = e.Reply;
int pingTime = (int)reply.RoundtripTime;
UnityEngine.Debug.Log(reply.RoundtripTime);
((AutoResetEvent)e.UserState).Set();
}
And It always return a RoundripTime which seems like a number make sense, but when I try to ping another ip address which is not available to reach or even turn off the internet it always return a RoundripTime with reply.status equals to IPStatus.Success. Now I'm confused, did I really ping to my remote server or not?
I did chekced some other similar questions, and it doesn't solved the problem. Some answers suggest to use SendPingAsync instead of SendAsync, but that is not possible for unity.
I have button.click event where i have this code ... and it works fine
AutoResetEvent waiter = new AutoResetEvent(false);
Ping pingSender = new Ping();
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 100;
PingOptions options = new PingOptions(64, true);
IPAddress address = IPAddress.Parse("YourTestIP");
PingReply reply = pingSender.Send(address, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
MessageBox.Show(reply.Address.ToString());
}
While making a c# application for remote controlling cisco routers using TCP, I got the problem of waiting for a response from the router.
For the application I have to connect to a Cisco router using a TCP connection. After the connection has been made a networkstream will push my command to the Cisco router. To let the router process the command, I am using Thread.Sleep. This is not the best solution.
Here is the complete code to get a idea what my program is doing.
string IPAddress = "192.168.1.1";
string message = "show running-config"; // command to run
int bytes;
string response = "";
byte[] responseInBytes = new byte[4096];
var client = new TcpClient();
client.ConnectAsync(IPAddress, 23).Wait(TimeSpan.FromSeconds(2));
if (client.Connected == true)
{
client.ReceiveTimeout = 3;
client.SendTimeout = 3;
byte[] messageInBytes = Encoding.ASCII.GetBytes(message);
NetworkStream stream = client.GetStream();
Console.WriteLine();
stream.Write(messageInBytes, 0, messageInBytes.Count()); //send data to router
Thread.Sleep(50); // temporary way to let the router fill his tcp response
bytes = stream.Read(responseInBytes, 0, responseInBytes.Length);
response = Encoding.ASCII.GetString(responseInBytes, 0, bytes);
return response; //whole command output
}
return null;
What is a good and reliable way to get the full response.
Thanks for any help or command.
More info:
The networksteam is always filled with something, most of the time it is filled with the cisco IOS login page. The biggest problem is to determine when the router is done filling up the response.
The response I most of the time get:
"??\u0001??\u0003??\u0018??\u001f\r\n\r\nUser Access Verification\r\n\r\nUsername: "
The return data will be diffent every time because it will be a result of a cisco command. This can vary from a short string to a very long string.
mrmathijs95 -
When reading from NetworkStream with Stream.Read it not 100% sure that you will read all expected data. Stream.Read can return when only few packet arrived and not waiting for others.
To be sure that you get all data use BinaryReader for reading.
BinaryReader.Read method will block current thread until all expected data arrived
private string GetResponse(string message)
{
const int RESPONSE_LENGTH = 4096;
byte[] messageInBytes = Encoding.ASCII.GetBytes(message);
bool leaveStreamOpen = true;
using(var writer = new BinaryWriter(client.GetStream()))
{
writer.Write(messageInBytes);
}
using(var reader = New BinaryReader(client.GetStream()))
{
byte[] bytes = reader.Read(RESPONSE_LENGTH );
return Encoding.ASCII.GetString(bytes);
}
}
Don't use Thread.Sleep. I would async/await the entire thing, given that you don't always know what the data is based on your recent edit. This is how I would do it (untested):
public class Program
{
// call Foo write with "show running-config"
}
public class Foo
{
private TcpClient _client;
private ConcurrentQueue<string> _responses;
private Task _continualRead;
private CancellationTokenSource _readCancellation;
public Foo()
{
this._responses = new ConcurrentQueue<string>();
this._readCancellation = new CancellationTokenSource();
this._continualRead = Task.Factory.StartNew(this.ContinualReadOperation, this._readCancellation.Token, this._readCancellation.Token);
}
public async Task<bool> Connect(string ip)
{
this._client = new TcpClient
{
ReceiveTimeout = 3, // probably shouldn't be 3ms.
SendTimeout = 3 // ^
};
int timeout = 1000;
return await this.AwaitTimeoutTask(this._client.ConnectAsync(ip, 23), timeout);
}
public async void StreamWrite(string message)
{
var messageBytes = Encoding.ASCII.GetBytes(message);
var stream = this._client.GetStream();
if (await this.AwaitTimeoutTask(stream.WriteAsync(messageBytes, 0, messageBytes.Length), 1000))
{
//write success
}
else
{
//write failure.
}
}
public async void ContinualReadOperation(object state)
{
var token = (CancellationToken)state;
var stream = this._client.GetStream();
var byteBuffer = new byte[4096];
while (!token.IsCancellationRequested)
{
int bytesLastRead = 0;
if (stream.DataAvailable)
{
bytesLastRead = await stream.ReadAsync(byteBuffer, 0, byteBuffer.Length, token);
}
if (bytesLastRead > 0)
{
var response = Encoding.ASCII.GetString(byteBuffer, 0, bytesLastRead);
this._responses.Enqueue(response);
}
}
}
private async Task<bool> AwaitTimeoutTask(Task task, int timeout)
{
return await Task.WhenAny(task, Task.Delay(timeout)) == task;
}
public void GetResponses()
{
//Do a TryDequeue etc... on this._responses.
}
}
I didn't expose the read cancellation publicly, but you could add this method to cancel the read operation:
public void Cancel()
{
this._readCancellation.Cancel();
}
And then dispose of your client and all that fun stuff.
Lastly, because you said there's always data available on the stream, where you're doing the read you may have to do some logic on the number of bytes last read to offset yourself within the stream if the data doesn't clear. You'll know if the responses you're getting is always the same.
This is the working code for me.
It uses the solution of Fabio,
combined with a while loop to check every X miliseconds if the response has changed.
client.ReceiveTimeout = 3;
client.SendTimeout = 3;
byte[] messageInBytes = Encoding.ASCII.GetBytes(message);
NetworkStream stream = client.GetStream();
Console.WriteLine();
using (var writer = new BinaryWriter(client.GetStream(),Encoding.ASCII,true))
{
writer.Write(messageInBytes);
}
using (var reader = new BinaryReader(client.GetStream(),Encoding.ASCII, true))
{
while (itIsTheEnd == false)
{
bytes = reader.Read(responseInBytes, 0, responseInBytes.Count());
if (lastBytesArray == responseInBytes)
{
itIsTheEnd = true;
}
lastBytesArray = responseInBytes;
Thread.Sleep(15);
}
}
response = Encoding.ASCII.GetString(responseInBytes);
Thanks for everyone who suggested a solution.
And thanks to Fabio for the given solution.
This question already has answers here:
What is the best way to check for Internet connectivity using .NET?
(27 answers)
Closed 8 years ago.
Can you please tell me if there is a way to check if there is a internet connection in my computer when my C# program is running. For a simple example, if internet is working, I would output a message box saying Internet is available. else I would output a message saying, Internet is unavailable.
Without using the library function to see if network is available (since this doesn't check internet connectivity)
System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()
Or without opening a webpage and seeing if it's return data
using (WebClient client = new WebClient())
htmlCode = client.DownloadString("http://google.com");
Because both of these above methods don't suit my needs.
a little shorter version:
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
catch
{
return false;
}
}
Another option is:
Ping myPing = new Ping();
String host = "google.com";
byte[] buffer = new byte[32];
int timeout = 1000;
PingOptions pingOptions = new PingOptions();
PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
if (reply.Status == IPStatus.Success) {
// presumably online
}
You can find a broader discussion here
Consider the following code snippet...
Ping myPing = new Ping();
String host = "google.com";
byte[] buffer = new byte[32];
int timeout = 1000;
PingOptions pingOptions = new PingOptions();
PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
if (reply.Status == IPStatus.Success)
{
// presumably online
}
Good Luck!
just wrote async functions to do that:
private void myPingCompletedCallback(object sender, PingCompletedEventArgs e)
{
if (e.Cancelled)
return;
if (e.Error != null)
return;
if (e.Reply.Status == IPStatus.Success)
{
//ok connected to internet, do something...
}
}
private void checkInternet()
{
Ping myPing = new Ping();
myPing.PingCompleted += new PingCompletedEventHandler(myPingCompletedCallback);
try
{
myPing.SendAsync("google.com", 3000 /*3 secs timeout*/, new byte[32], new PingOptions(64, true));
}
catch
{
}
}
My NetworkMonitor class now provides this (based on other responses here):
public bool IsInternetAvailable
{
get { return IsNetworkAvailable && _CanPingGoogle(); }
}
private static bool _CanPingGoogle()
{
const int timeout = 1000;
const string host = "google.com";
var ping = new Ping();
var buffer = new byte[32];
var pingOptions = new PingOptions();
try {
var reply = ping.Send(host, timeout, buffer, pingOptions);
return (reply != null && reply.Status == IPStatus.Success);
}
catch (Exception) {
return false;
}
}
This is my approach;
Check that a network connection is available, if it isn't then we wont be able to connect to another host.
Check if we can connect to some major hosts. Use a fallback just in case that site isn't available.
public static bool ConnectToInternet(int timeout_per_host_millis = 1000, string[] hosts_to_ping = null)
{
bool network_available = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
if (network_available)
{
string[] hosts = hosts_to_ping ?? new string[] { "www.google.com", "www.facebook.com" };
Ping p = new Ping();
foreach (string host in hosts)
{
try
{
PingReply r = p.Send(host, timeout_per_host_millis);
if (r.Status == IPStatus.Success)
return true;
}
catch { }
}
}
return false;
}
Notes:
Don't use too many hosts when reaching out, weigh up the cost in time of making all the pings against the diminishing likelihood of success.
If we send the ping to a certain that host we intend to connect to later (eg a http request) a returned ping doesn't mean we are connected to that particular host. Consider what would happen if the host is blocked. eg Facebook is blocked in Iran,China,... Does that ISP return the ping?
A DNS request wont be sufficient as it may be cached
public static bool HasConnection()
{
try
{
System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry("www.google.com");
return true;
}
catch
{
return false;
}
}
Rrom C#, reading/writing over SOCKET to JAVA and having some concurrency/socket issue.
I am trying to implement a server client application where the server is Java and the Client is C#. And they communicate over TCP/IP and exchanging some binary data between them.
Particularly I have a Packet class defined both in Java and C#. It has a header, key and value. Both Java and C# writes and reads the Packet to Socket in exact same way. This way I am able to send a request Packet from C#, process it on Java Server and send the response back as a Packet.
The original problem is way more complicated but I was able to boil it down to this "Simple" version.
I have implemented both server and client as described below. The code is also available at the bottom.
For me to state the problem you have to continue to read:)
Server(Java) side
On Server side I have a very dummy ServerSocket usage. It reads the incoming Packets and sends back almost the same Packet as response.
Client(C#) side
The client is a bit complicated. Client starts N(configurable) number of threads(I'll call them user threads). One In Thread and One Out Thread. All user threads create a Call object with dummy request Packet and unique id. Then adds the call into a local BlockingCollection.
The Out Thread continuously reads the local BlockingCollection and sends all request packets to server
The In Thread also continuously reads response Packets from server and matches them to the Call objects(remember the unique call id).
If there is no response for a particular Call object within 5 sec intervals the user thread will complain about it by printing into Console.
Also there is a timer with 10 sec interval that prints how many transactions have been executed per second.
If you reached so far, thank you:).
Now the problem:
The code below, which is the implementation of what I described above works fine with Mono on Mac. On Windows it also doesn't fail immediately with low number(<10) of user threads. As I increase the number of threads suddenly, somehow the response packets that client receives are getting corrupted. In terms of this application all user threads get stuck because the answer to their request is not received.
The question is why they are corrupted? As you see the threads that touche socket are In and Out threads. But somehow the amount of user threads affects the client and brakes it.
It looks like some concurrency or socket problem, but I could find it.
I have put the code for Server(Java) and Client(C#). They don't have any dependency just compiling and running the Main methods on both(first server) shows the problem.
I appreciate if you read so far.
Server Code
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
public class DummyServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9900);
System.out.println("Server started");
for(;;){
final Socket socket = server.accept();
System.out.println("Accepting a connection");
new Thread(new Runnable(){
public void run() {
try {
System.out.println("Thread started to handle the connection");
DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
for(int i=0; ; i++){
Packet packet = new Packet();
packet.readFrom(dis);
packet.key = null;
packet.value = new byte[1000];
packet.writeTo(dos);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
public static class Packet {
byte[] key;
byte[] value;
long callId = -1;
private int valueHash = -1;
public void writeTo(DataOutputStream outputStream) throws IOException {
final ByteBuffer writeHeaderBuffer = ByteBuffer.allocate(1 << 10); // 1k
writeHeaderBuffer.clear();
writeHeaderBuffer.position(12);
writeHeaderBuffer.putLong(callId);
writeHeaderBuffer.putInt(valueHash);
int size = writeHeaderBuffer.position();
int headerSize = size - 12;
writeHeaderBuffer.position(0);
writeHeaderBuffer.putInt(headerSize);
writeHeaderBuffer.putInt((key == null) ? 0 : key.length);
writeHeaderBuffer.putInt((value == null) ? 0 : value.length);
outputStream.write(writeHeaderBuffer.array(), 0, size);
if (key != null)outputStream.write(key);
if (value != null)outputStream.write(value);
}
public void readFrom(DataInputStream dis) throws IOException {
final ByteBuffer readHeaderBuffer = ByteBuffer.allocate(1 << 10);
final int headerSize = dis.readInt();
int keySize = dis.readInt();
int valueSize = dis.readInt();
readHeaderBuffer.clear();
readHeaderBuffer.limit(headerSize);
dis.readFully(readHeaderBuffer.array(), 0, headerSize);
this.callId = readHeaderBuffer.getLong();
valueHash = readHeaderBuffer.getInt();
key = new byte[keySize];
dis.readFully(key);
value = new byte[valueSize];
dis.readFully(value);
}
}
}
C# Client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Collections.Concurrent;
using System.Threading;
namespace Client
{
public class Program
{
readonly ConcurrentDictionary<long, Call> calls = new ConcurrentDictionary<long, Call>();
readonly BlockingCollection<Call> outThreadQueue = new BlockingCollection<Call>(1000);
readonly TcpClient tcpClient = new TcpClient("localhost", 9900);
readonly private int THREAD_COUNT;
static int ops;
public static void Main(string[] args) {
new Program(args.Length > 0 ? int.Parse(args[0]) : 100).Start();
}
public Program(int threadCount) {
this.THREAD_COUNT = threadCount;
new Thread(new ThreadStart(this.InThreadRun)).Start();//start the InThread
new Thread(new ThreadStart(this.OutThreadRun)).Start();//start the OutThread
}
public void Start(){
for (int i = 0; i < THREAD_COUNT; i++)
new Thread(new ThreadStart(this.Call)).Start();
Console.WriteLine(THREAD_COUNT + " User Threads started to perform server call");
System.Timers.Timer aTimer = new System.Timers.Timer(10000);
aTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.Stats);
aTimer.Enabled = true;
}
public void Stats(object source, System.Timers.ElapsedEventArgs e){
Console.WriteLine("Ops per second: " + Interlocked.Exchange(ref ops, 0) / 10);
}
public void Call() {
for (; ;){
Call call = new Call(new Packet());
call.request.key = new byte[10];
call.request.value = new byte[1000];
outThreadQueue.Add(call);
Packet result = null;
for (int i = 1;result==null ; i++){
result = call.getResult(5000);
if(result==null) Console.WriteLine("Call" + call.id + " didn't get answer within "+ 5000*i/1000 + " seconds");
}
Interlocked.Increment(ref ops);
}
}
public void InThreadRun(){
for (; ; ){
Packet packet = new Packet();
packet.Read(tcpClient.GetStream());
Call call;
if (calls.TryGetValue(packet.callId, out call))
call.inbQ.Add(packet);
else
Console.WriteLine("Unkown call result: " + packet.callId);
}
}
public void OutThreadRun() {
for (; ; ){
Call call = outThreadQueue.Take();
calls.TryAdd(call.id, call);
Packet packet = call.request;
if (packet != null) packet.write(tcpClient.GetStream());
}
}
}
public class Call
{
readonly public long id;
readonly public Packet request;
static long callIdGen = 0;
readonly public BlockingCollection<Packet> inbQ = new BlockingCollection<Packet>(1);
public Call(Packet request)
{
this.id = incrementCallId();
this.request = request;
this.request.callId = id;
}
public Packet getResult(int timeout)
{
Packet response = null;
inbQ.TryTake(out response, timeout);
return response;
}
private static long incrementCallId()
{
long initialValue, computedValue;
do
{
initialValue = callIdGen;
computedValue = initialValue + 1;
} while (initialValue != Interlocked.CompareExchange(ref callIdGen, computedValue, initialValue));
return computedValue;
}
}
public class Packet
{
public byte[] key;
public byte[] value;
public long callId = 0;
public void write(Stream stream)
{
MemoryStream header = new MemoryStream();
using (BinaryWriter writer = new BinaryWriter(header))
{
writer.Write(System.Net.IPAddress.HostToNetworkOrder((long)callId));
writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)-1));
}
byte[] headerInBytes = header.ToArray();
MemoryStream body = new MemoryStream();
using (BinaryWriter writer = new BinaryWriter(body))
{
writer.Write(System.Net.IPAddress.HostToNetworkOrder(headerInBytes.Length));
writer.Write(System.Net.IPAddress.HostToNetworkOrder(key == null ? 0 : key.Length));
writer.Write(System.Net.IPAddress.HostToNetworkOrder(value == null ? 0 : value.Length));
writer.Write(headerInBytes);
if (key != null) writer.Write(key);
if (value != null) writer.Write(value);
byte[] packetInBytes = body.ToArray();
stream.Write(packetInBytes, 0, packetInBytes.Length);
}
}
public void Read(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
int headerSize = IPAddress.NetworkToHostOrder(reader.ReadInt32());
int keySize = IPAddress.NetworkToHostOrder(reader.ReadInt32());
int valueSize = IPAddress.NetworkToHostOrder(reader.ReadInt32());
this.callId = IPAddress.NetworkToHostOrder(reader.ReadInt64());
int valuePartitionHash = IPAddress.NetworkToHostOrder(reader.ReadInt32());
this.key = new byte[keySize];
this.value = new byte[valueSize];
if (keySize > 0) reader.Read(this.key, 0, keySize);
if (valueSize > 0) reader.Read(this.value, 0, valueSize);
}
}
}
This is a pretty common mistake: any Read call on a socket may not actually read as many bytes as you ask for, if they are not currently available. Read will return the number of bytes read by each call. If you expect to read n bytes of data, then you need to call read multiple times until the number of bytes read adds up to n.