In my Xamarin Forms application, I am trying to discover all devices on the local network that I am connected to. My approach is to first get the device IP address, and use to first 3 numbers to know what the gateway is (first number is always 192). And then, ping every address on that gateway. Here is my code:
public partial class MainPage : ContentPage
{
private List<Device> discoveredDevices = new List<Device>();
public MainPage()
{
InitializeComponent();
Ping_all();
}
private string GetCurrentIp()
{
IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());
string ipAddress = string.Empty;
if (addresses != null && addresses[0] != null)
{
ipAddress = addresses[0].ToString();
}
else
{
ipAddress = null;
}
return ipAddress;
}
public void Ping_all()
{
string ip = GetCurrentIp();
if (ip != null)
{
//Extracting and pinging all other ip's.
string[] array = ip.Split('.');
string gateway = array[0] + "." + array[1] + "." + array[2];
for (int i = 2; i <= 255; i++)
{
string ping_var = $"{gateway}.{i}";
//time in milliseconds
Ping(ping_var, 4, 4000);
}
}
}
public void Ping(string host, int attempts, int timeout)
{
for (int i = 0; i < attempts; i++)
{
new Thread(delegate ()
{
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
ping.SendAsync(host, timeout, host);
// PingCompleted never gets called
}
catch(Exception e)
{
// Do nothing and let it try again until the attempts are exausted.
// Exceptions are thrown for normal ping failurs like address lookup
// failed. For this reason we are supressing errors.
}
}).Start();
}
}
private void PingCompleted(object sender, PingCompletedEventArgs e)
{
string ip = (string)e.UserState;
if (e.Reply != null && e.Reply.Status == IPStatus.Success)
{
string hostname = GetHostName(ip);
string macaddres = GetMacAddress(ip);
var device = new Device()
{
Hostname = hostname,
IpAddress = ip,
MacAddress = macaddres
};
discoveredDevices.Add(device);
}
}
public string GetHostName(string ipAddress)
{
try
{
IPHostEntry entry = Dns.GetHostEntry(ipAddress);
if (entry != null)
{
return entry.HostName;
}
}
catch (SocketException)
{
}
return null;
}
public string GetMacAddress(string ipAddress)
{
string macAddress = string.Empty;
System.Diagnostics.Process Process = new System.Diagnostics.Process();
Process.StartInfo.FileName = "arp";
Process.StartInfo.Arguments = "-a " + ipAddress;
Process.StartInfo.UseShellExecute = false;
Process.StartInfo.RedirectStandardOutput = true;
Process.StartInfo.CreateNoWindow = true;
Process.Start();
string strOutput = Process.StandardOutput.ReadToEnd();
string[] substrings = strOutput.Split('-');
if (substrings.Length >= 8)
{
macAddress = substrings[3].Substring(Math.Max(0, substrings[3].Length - 2))
+ "-" + substrings[4] + "-" + substrings[5] + "-" + substrings[6]
+ "-" + substrings[7] + "-"
+ substrings[8].Substring(0, 2);
return macAddress;
}
else
{
return "OWN Machine";
}
}
}
I get to the part where I try to ping:
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
ping.SendAsync(host, timeout, host);
But PingCompleted never gets called. No exception is thrown either. Any idea why? I'm running this on a physical Android device.
EDIT
PingCompleted started getting called for me now, not sure why it wasn't working before. But it now crashes in my GetMacAddress function on the line Process.Start(); because it can not find the resource.
I ended up using this really robust and easy to use library:
https://github.com/Yortw/RSSDP
It doesn't actually find all devices on the network, instead it uses SSDP (Simple Search Discovery Protocol) to quickly find all devices that are broadcasting a service with this protocol on the network. I filtered it to only scan devices running my app, which is what I actually needed. It takes only a second to discover my devices, which is much faster than pinging 255 addresses.
In the documentation you will see:
var deviceDefinition = new SsdpRootDevice()
{
CacheLifetime = TimeSpan.FromMinutes(30), //How long SSDP clients can cache this info.
Location = new Uri("http://mydevice/descriptiondocument.xml"), // Must point to the URL that serves your devices UPnP description document.
DeviceTypeNamespace = "my-namespace",
DeviceType = "MyCustomDevice",
FriendlyName = "Custom Device 1",
Manufacturer = "Me",
ModelName = "MyCustomDevice",
Uuid = GetPersistentUuid() // This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
};
For the Location I set it as my device's IP. So that another device that discovers it can have the IP too. I don't think it's meant to be used this way, but it worked for me and I don't see why not.
I tested it on 2 physical Android devices.
Related
I'm trying to start my "webserver" on all local IP's. So I have to send a string to WebServer ws = new WebServer(SendResponse, IPs.GetIPs("program"));, and a Array to static string[] uris.
Now it only receives one IP, tried some other ways like sending a string to WebServer ws = new WebServer(SendResponse, IPs.GetIPs("program")); but that also didn't work with multiple IP's.
It needs to return a string for program and a array for webserver.
The string should be something like this: "http://192.168.0.107:1337/", "http://192.168.56.1:1337/" for program.
How would I send more then 1 argument to a function and to a array. I know this code doesn't work but I'm desperate right now to get this working.
IPs.cs:
public static string GetIPs(string args)
{
string[] combinedString = { };
List<string> IPAdressenLijst = new List<string>();
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress ip in ips)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
if (args == "program")
{
IPAdressenLijst.Add("http://" + ip + ":1337/");
combinedString = IPAdressenLijst.ToArray();
}
else if (args == "webserver")
{
IPAdressenLijst.Add("http://" + ip + ":1337/start/");
IPAdressenLijst.Add("http://" + ip + ":1337/stop/");
combinedString = IPAdressenLijst.ToArray();
}
}
}
return combinedString[0];
}
Program.cs:
static void Main(string[] args)
{
Console.WriteLine(DateTime.Now + " Press any key to exit.");
//WebServer ws = new WebServer(SendResponse, "http://192.168.0.107:1337/", "http://localhost:1337/");
WebServer ws = new WebServer(SendResponse, IPs.GetIPs("program"));
ws.Run();
Console.ReadKey();
ws.Stop();
}
public static string SendResponse(HttpListenerRequest request)
{
return string.Format("TEST");
}
WebServer.cs:
public class WebServer
{
//static string[] uris =
//{
// "http://192.168.0.107:1337/start/",
// "http://192.168.0.107:1337/stop/"
//};
static string[] uris =
{
IPs.GetIPs("webserver")
};
}
To start a TcpListener (for your webserver) you can use the IPAddress.Any address like below:
var server = new TcpListener(IPAddress.Any, port);
Now, to your code: The GetIPs function has bunch of issues. While you loop, you keep overwriting combinedString, every time. To top it, you actually just return the first item from combinedString. From the context of the question, I gather that you want to return all IP addresses and not just one
This is how that function should be
public static List<string> GetIPs(string args) {
var ipAdressenLijst = new List<string>();
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress ip in ips) {
if (ip.AddressFamily == AddressFamily.InterNetwork) {
if (args == "program") {
ipAdressenLijst.Add("http://" + ip + ":1337/");
} else if (args == "webserver") {
ipAdressenLijst.Add("http://" + ip + ":1337/start/");
ipAdressenLijst.Add("http://" + ip + ":1337/stop/");
}
}
}
return ipAdressenLijst;
}
Your Webserver.cs code should look like this to handle the incoming array of URIs.
public class WebServer {
string[] Uris;
public WebServer(Func<HttpListenerRequest, string> sendResponse, IEnumerable<string> ipAdressenLijst)
{
Uris = ipAdressenLijst.ToArray();
}
}
In Main function in Program.cs, your call should look like
WebServer ws = new WebServer(SendResponse, IPs.GetIPs("webserver"));
There is a lot of guess work on my side, as not all information is available in your question.. Let me know if that makes sense and works for you
I am new in c#, I have a form that receive "+:0" from some machine by ethernet in LAN using arduino,
the "0" will increase if the same machine send "+" again.
Each pc will randomly send "+" to the form.
the problem is, if the machine A has reached "+:5" and the machine B has just started to send the data("+:0"),
how do I store the temporary data (not stored to database, just in c#) for machine A to proccess the machine B until
the machine A is called back again? Is there any way to do it?
This is my code to get data from IP:
The downloadedStringwill accept "+:0" if the machine send the first data.
public AndonForm()
{
InitializeComponent();
_timer.Interval = (500) * (1);
_timer.Enabled = true;
_timer.Start();
_timer.Tick += (timerTick);
}
private void timerTick(object sender, EventArgs e)
{
GetDataFromArduino("http://192.168.1.200/");
GetDataFromArduino("http://192.168.1.12/");
GetDataFromArduino("http://192.168.1.166/");
GetDataFromArduino("http://192.168.1.6/");
}
private void GetDataFromArduino(string ipAddress)
{
WebClient client = new WebClient();
String downloadedString = client.DownloadString(ipAddress);
if (downloadedString.Contains("SPP"))
{
downloadedString = downloadedString.Split(new[] { "<html>\r\n" }, StringSplitOptions.None)[1];
tempDownloadString = downloadedString.Substring(0, downloadedString.IndexOf(":"));
tempCount = downloadedString.Split(new[] { ":" }, StringSplitOptions.None)[1];
}
else if (downloadedString.Contains("NPK"))
{
downloadedString = downloadedString.Split(new[] {"<html>\r\n"}, StringSplitOptions.None)[1];
tempDownloadString = downloadedString.Substring(0, downloadedString.IndexOf(":"));
tempCount = downloadedString.Split(new[] { ":" }, StringSplitOptions.None)[1];
tempCount = tempCount.Substring(0, tempCount.IndexOf("<"));
}
else
{
downloadedString = downloadedString.Split(new[] {"<html>\r\n"}, StringSplitOptions.None)[1];
tempDownloadString = downloadedString.Substring(0, downloadedString.IndexOf(":"));
tempCount = downloadedString.Split(new[] {":"}, StringSplitOptions.None)[1];
tempCount = tempCount.Substring(0, tempCount.IndexOf("<"));
}
if (SPP != null && NPK == null)
{
finalDownloadString = tempDownloadString;
si_DataReceived(tempDownloadString);
x = tempCount;
}
else if (SPP != null && NPK !=null)
{
if (x != tempCount || tempDownloadString != finalDownloadString)
{
si_DataReceived(tempDownloadString);
finalDownloadString = tempDownloadString;
x = tempCount;
}
}
else
{
finalDownloadString = tempDownloadString;
si_DataReceived(tempDownloadString);
x = tempCount;
}
}
You can use a Dictionary<string, List<string>>. In your Dictionary the key string should be the ip in ipAddress variable and List<string> are all data send by Arduino for the specific ip.
I want the public IP address of the client who is using my website.
The code below is showing the local IP in the LAN, but I want the public IP of the client.
//get mac address
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
String sMacAddress = string.Empty;
foreach (NetworkInterface adapter in nics)
{
if (sMacAddress == String.Empty)// only return MAC Address from first card
{
IPInterfaceProperties properties = adapter.GetIPProperties();
sMacAddress = adapter.GetPhysicalAddress().ToString();
}
}
// To Get IP Address
string IPHost = Dns.GetHostName();
string IP = Dns.GetHostByName(IPHost).AddressList[0].ToString();
Output:
Ip Address : 192.168.1.7
Please help me to get the public IP address.
This is what I use:
protected void GetUser_IP()
{
string VisitorsIPAddr = string.Empty;
if (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
{
VisitorsIPAddr = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
}
else if (HttpContext.Current.Request.UserHostAddress.Length != 0)
{
VisitorsIPAddr = HttpContext.Current.Request.UserHostAddress;
}
uip.Text = "Your IP is: " + VisitorsIPAddr;
}
"uip" is the name of the label in the aspx page that shows the user IP.
You can use "HTTP_X_FORWARDED_FOR" or "REMOTE_ADDR" header attribute.
Refer method GetVisitorIPAddress from Machine Syntax blog .
/// <summary>
/// method to get Client ip address
/// </summary>
/// <param name="GetLan"> set to true if want to get local(LAN) Connected ip address</param>
/// <returns></returns>
public static string GetVisitorIPAddress(bool GetLan = false)
{
string visitorIPAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (String.IsNullOrEmpty(visitorIPAddress))
visitorIPAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
if (string.IsNullOrEmpty(visitorIPAddress))
visitorIPAddress = HttpContext.Current.Request.UserHostAddress;
if (string.IsNullOrEmpty(visitorIPAddress) || visitorIPAddress.Trim() == "::1")
{
GetLan = true;
visitorIPAddress = string.Empty;
}
if (GetLan && string.IsNullOrEmpty(visitorIPAddress))
{
//This is for Local(LAN) Connected ID Address
string stringHostName = Dns.GetHostName();
//Get Ip Host Entry
IPHostEntry ipHostEntries = Dns.GetHostEntry(stringHostName);
//Get Ip Address From The Ip Host Entry Address List
IPAddress[] arrIpAddress = ipHostEntries.AddressList;
try
{
visitorIPAddress = arrIpAddress[arrIpAddress.Length - 2].ToString();
}
catch
{
try
{
visitorIPAddress = arrIpAddress[0].ToString();
}
catch
{
try
{
arrIpAddress = Dns.GetHostAddresses(stringHostName);
visitorIPAddress = arrIpAddress[0].ToString();
}
catch
{
visitorIPAddress = "127.0.0.1";
}
}
}
}
return visitorIPAddress;
}
Combination of all of these suggestions, and the reasons behind them. Feel free to add more test cases too. If getting the client IP is of utmost importance, than you might wan to get all of theses are run some comparisons on which result might be more accurate.
Simple check of all suggestions in this thread plus some of my own code...
using System.IO;
using System.Net;
public string GetUserIP()
{
string strIP = String.Empty;
HttpRequest httpReq = HttpContext.Current.Request;
//test for non-standard proxy server designations of client's IP
if (httpReq.ServerVariables["HTTP_CLIENT_IP"] != null)
{
strIP = httpReq.ServerVariables["HTTP_CLIENT_IP"].ToString();
}
else if (httpReq.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
{
strIP = httpReq.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
}
//test for host address reported by the server
else if
(
//if exists
(httpReq.UserHostAddress.Length != 0)
&&
//and if not localhost IPV6 or localhost name
((httpReq.UserHostAddress != "::1") || (httpReq.UserHostAddress != "localhost"))
)
{
strIP = httpReq.UserHostAddress;
}
//finally, if all else fails, get the IP from a web scrape of another server
else
{
WebRequest request = WebRequest.Create("http://checkip.dyndns.org/");
using (WebResponse response = request.GetResponse())
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
strIP = sr.ReadToEnd();
}
//scrape ip from the html
int i1 = strIP.IndexOf("Address: ") + 9;
int i2 = strIP.LastIndexOf("</body>");
strIP = strIP.Substring(i1, i2 - i1);
}
return strIP;
}
That code gets you the IP address of your server not the address of the client who is accessing your website. Use the HttpContext.Current.Request.UserHostAddress property to the client's IP address.
For Web Applications ( ASP.NET MVC and WebForm )
/// <summary>
/// Get current user ip address.
/// </summary>
/// <returns>The IP Address</returns>
public static string GetUserIPAddress()
{
var context = System.Web.HttpContext.Current;
string ip = String.Empty;
if (context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
ip = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
else if (!String.IsNullOrWhiteSpace(context.Request.UserHostAddress))
ip = context.Request.UserHostAddress;
if (ip == "::1")
ip = "127.0.0.1";
return ip;
}
For Windows Applications ( Windows Form, Console, Windows Service , ... )
static void Main(string[] args)
{
HTTPGet req = new HTTPGet();
req.Request("http://checkip.dyndns.org");
string[] a = req.ResponseBody.Split(':');
string a2 = a[1].Substring(1);
string[] a3=a2.Split('<');
string a4 = a3[0];
Console.WriteLine(a4);
Console.ReadLine();
}
So many of these code snippets are really big and could confuse new programmers looking for help.
How about this simple and compact code to fetch the IP address of the visitor?
string ip = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(ip))
{
ip = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
Simple, short and compact.
I have an extension method:
public static string GetIp(this HttpContextBase context)
{
if (context == null || context.Request == null)
return string.Empty;
return context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]
?? context.Request.UserHostAddress;
}
Note: "HTTP_X_FORWARDED_FOR" is for ip behind proxy. context.Request.UserHostAddress is identical to "REMOTE_ADDR".
But bear in mind it is not necessary the actual IP though.
Sources:
IIS Server Variables
Link
My version handles both ASP.NET or LAN IPs:
/**
* Get visitor's ip address.
*/
public static string GetVisitorIp() {
string ip = null;
if (HttpContext.Current != null) { // ASP.NET
ip = string.IsNullOrEmpty(HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"])
? HttpContext.Current.Request.UserHostAddress
: HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
}
if (string.IsNullOrEmpty(ip) || ip.Trim() == "::1") { // still can't decide or is LAN
var lan = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(r => r.AddressFamily == AddressFamily.InterNetwork);
ip = lan == null ? string.Empty : lan.ToString();
}
return ip;
}
private string GetClientIpaddress()
{
string ipAddress = string.Empty;
ipAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (ipAddress == "" || ipAddress == null)
{
ipAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
return ipAddress;
}
else
{
return ipAddress;
}
}
On MVC 5 you can use this:
string cIpAddress = Request.UserHostAddress; //Gets the client ip address
or
string cIpAddress = Request.ServerVariables["REMOTE_ADDR"]; //Gets the client ip address
In MVC IP can be obtained by the following Code
string ipAddress = Request.ServerVariables["REMOTE_ADDR"];
string IP = HttpContext.Current.Request.Params["HTTP_CLIENT_IP"] ?? HttpContext.Current.Request.UserHostAddress;
just use this..................
public string GetIP()
{
string externalIP = "";
externalIP = (new WebClient()).DownloadString("http://checkip.dyndns.org/");
externalIP = (new Regex(#"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}")).Matches(externalIP)[0].ToString();
return externalIP;
}
We connect to servers that give us our external IP address and try to parse the IP from returning HTML pages. But when servers make small changes on these pages or remove them, these methods stop working properly.
Here is a method that takes the external IP address using a server which has been alive for years and returns a simple response rapidly...
https://www.codeproject.com/Tips/452024/Getting-the-External-IP-Address
Private string getExternalIp()
{
try
{
string externalIP;
externalIP = (new
WebClient()).DownloadString("http://checkip.dyndns.org/");
externalIP = (new Regex(#"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"))
.Matches(externalIP)[0].ToString();
return externalIP;
}
catch { return null; }
}
VB.NET
Imports System.Net
Private Function GetExternalIp() As String
Try
Dim ExternalIP As String
ExternalIP = (New WebClient()).DownloadString("http://checkip.dyndns.org/")
ExternalIP = (New Regex("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}")) _
.Matches(ExternalIP)(0).ToString()
Return ExternalIP
Catch
Return Nothing
End Try
End Function
lblmessage.Text =Request.ServerVariables["REMOTE_HOST"].ToString();
You can download xNet at: https://drive.google.com/open?id=1fmUosINo8hnDWY6s4IV4rDnHKLizX-Hq
First, you need import xNet, code:
using xNet;
Code:
void LoadpublicIP()
{
HttpRequest httprequest = new HttpRequest();
String HTML5 = httprequest.Get("https://whoer.net/").ToString();
MatchCollection collect = Regex.Matches(HTML5, #"<strong data-clipboard-target="".your-ip(.*?)</strong>", RegexOptions.Singleline);
foreach (Match match in collect)
{
var val = Regex.Matches(match.Value, #"(?<ip>(\d|\.)+)");
foreach (Match m in val)
{
richTextBox1.Text = m.Groups[2].Value;
}
}
}
there
I want to get a result that if there is wireless adapter on my Linux device by C#/mono.
If I use command "iwconfig" if wireless adapter attached, here is the result:
lo no wireless extensions.
eth0 no wireless extensions.
wlan0 IEEE 802.11bg ESSID:off/any
Mode:Managed Access Point: Not-Associated
Encryption key:off
Power Management:on
if not attached,the result is :
lo no wireless extensions.
eth0 no wireless extensions.
I want to System.Net.NetworkInformation.NetworkInterface.NetworkInterfaceType to get it,but it seem that for "eth0" and "wlan0", the return result both are "Ethernet".
So my question is there any other method to distinguish the wireless adapter? Thanks.
You can do one of:
Check if the interface appears in /proc/net/wireless.
Create a socket and invoke SIOCGIWNAME on it, passing the interface name.
Attempt whatever wireless-specific task you want and see if it fails.
A possible solution for #2 is:
using System;
using System.Net.NetworkInformation;
using System.Net.Sockets;
public class App
{
public static int Main (string[] args)
{
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Unspecified);
foreach(NetworkInterface nic in nics)
{
byte[] name = System.Text.Encoding.ASCII.GetBytes(nic.Description);
byte[] request = new byte[32];
Array.Copy(name, request, name.Length);
bool wireless;
try
{
// SIOCGIWNAME is 0x8b01
socket.IOControl(0x8b01, request, request);
wireless = true;
} catch (SocketException) {
wireless = false;
}
Console.WriteLine("{0} wireless={1}", nic.Description, wireless);
}
return 0;
}
}
I have another answer,maybe not official, but does works.
private Process _proCheckWLANInterface;
private bool CheckWirelessAdapter()
{
bool flag = false;
InitProcess(out _proCheckWLANInterface,"iwconfig","");
string strResults = executeCmd(_proCheckWLANInterface);
var datas = strResults.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (var item in datas)
{
if (item.Contains("IEEE 802.11"))
{
flag= true;
break;
}
else
{
logger.Warn("Does not attached Wi-Fi Radio");
}
}
return flag;
}
private void InitProcess(out Process pro,string cmd, string args)
{
pro = new Process();
pro.StartInfo = new ProcessStartInfo();
pro.StartInfo.FileName = cmd;
pro.StartInfo.Arguments = args;
pro.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pro.StartInfo.RedirectStandardOutput = true;
pro.StartInfo.UseShellExecute = false;
pro.StartInfo.CreateNoWindow = true;
}
private string executeCmd(Process pro)
{
try
{
pro.Start();
pro.WaitForExit();
//logger.Trace(pro.StandardOutput.ReadToEnd());
return pro.StandardOutput.ReadToEnd();
}
catch (Exception ex)
{
logger.Debug("Exception in executeCmd method:", ex);
}
finally
{
pro.Close();
pro.Dispose();
pro = null;
}
return string.Empty;
}
I need to list IP addresses of all connected hosts in my LAN.
What is the simplest way to do this?
You'll have to do a ping sweep. There's a Ping class in the System.Net namespace. Example follows. Also this is only possible if your computers don't have firewalls running. If they've got a firewall enabled, there's no way to determine this information short of doing SNMP queries on your switches.
System.Net.NetworkInformation.Ping p = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply rep = p.Send("192.168.1.1");
if (rep.Status == System.Net.NetworkInformation.IPStatus.Success)
{
//host is active
}
The other issue is to determine how large your network is. In most home situations, your network mask will be 24 bits. This means that its set to 255.255.255.0. If your gateway is 192.168.1.1, this means that valid addresses on your network will be 192.168.1.1 to 192.168.1.254. Here's an IP Calculator to help. You'll have to loop through each address and ping the address using the Ping class and check the PingReply.
If you're just looking for the information and aren't concerned with how you get it, you can use NMap. The command would be as follows
nmap -sP 192.168.1.0/24
EDIT:
As far as speed goes, since you're on a local network, you can cut down the timeout interval considerably as your machines shouldn't take more than 100 milliseconds to reply. You can also use SendAsync to ping them all in parallel. The following program will ping 254 address in under half a second.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.NetworkInformation;
using System.Diagnostics;
using System.Net;
using System.Threading;
using System.Net.Sockets;
namespace ConsoleApplication1
{
class Program
{
static CountdownEvent countdown;
static int upCount = 0;
static object lockObj = new object();
const bool resolveNames = true;
static void Main(string[] args)
{
countdown = new CountdownEvent(1);
Stopwatch sw = new Stopwatch();
sw.Start();
string ipBase = "10.22.4.";
for (int i = 1; i < 255; i++)
{
string ip = ipBase + i.ToString();
Ping p = new Ping();
p.PingCompleted += new PingCompletedEventHandler(p_PingCompleted);
countdown.AddCount();
p.SendAsync(ip, 100, ip);
}
countdown.Signal();
countdown.Wait();
sw.Stop();
TimeSpan span = new TimeSpan(sw.ElapsedTicks);
Console.WriteLine("Took {0} milliseconds. {1} hosts active.", sw.ElapsedMilliseconds, upCount);
Console.ReadLine();
}
static void p_PingCompleted(object sender, PingCompletedEventArgs e)
{
string ip = (string)e.UserState;
if (e.Reply != null && e.Reply.Status == IPStatus.Success)
{
if (resolveNames)
{
string name;
try
{
IPHostEntry hostEntry = Dns.GetHostEntry(ip);
name = hostEntry.HostName;
}
catch (SocketException ex)
{
name = "?";
}
Console.WriteLine("{0} ({1}) is up: ({2} ms)", ip, name, e.Reply.RoundtripTime);
}
else
{
Console.WriteLine("{0} is up: ({1} ms)", ip, e.Reply.RoundtripTime);
}
lock(lockObj)
{
upCount++;
}
}
else if (e.Reply == null)
{
Console.WriteLine("Pinging {0} failed. (Null Reply object?)", ip);
}
countdown.Signal();
}
}
}
EDIT: After some use of it myself, I modified the program to output a count of how many IPs responded. There's a const bool that if set to true, will cause the program resolve the host names of the IPs. This significantly slows down the scan, though. (under half a second to 16 seconds) Also found that if the IP address is incorrectly specified (made a typo myself), the reply object can be null, so I handled that.
You would need to build an address range (e.g. 192.168.0.1 - 192.168.255.254) and ping each of those addresses. If a response is received, then that host is active.
Asynchronous Ping Tutorial:
http://www.geekpedia.com/tutorial234_Asynchronous-Ping-using-Csharp.html
However, some newer operating systems block ping requests (ICMP). This would need to be disabled in the firewall on each computer for you to receive a response.
You can do it all in managed code. I do it using System.DirectoryServices and System.Net. Basically I get the names of the local computers from DirectoryServices (handling domains and workgroups as I go) then get each host's IP addresses from System.Net.Dns. Here's everything packed into a handy class...
public class NetworkComputer {
private string _domain;
private string _name;
private IPAddress[] _addresses = null;
public string Domain { get { return _domain; } }
public string Name { get { return _name; } }
public IPAddress[] Addresses { get { return _addresses; } }
private NetworkComputer(string domain, string name) {
_domain = domain;
_name = name;
try { _addresses = Dns.GetHostAddresses(name); } catch { }
}
public static NetworkComputer[] GetLocalNetwork() {
var list = new List<NetworkComputer>();
using(var root = new DirectoryEntry("WinNT:")) {
foreach(var _ in root.Children.OfType<DirectoryEntry>()) {
switch(_.SchemaClassName) {
case "Computer":
list.Add(new NetworkComputer("", _.Name));
break;
case "Domain":
list.AddRange(_.Children.OfType<DirectoryEntry>().Where(__ => (__.SchemaClassName == "Computer")).Select(__ => new NetworkComputer(_.Name, __.Name)));
break;
}
}
}
return list.OrderBy(_ => _.Domain).ThenBy(_ => _.Name).ToArray();
}
}
Then just call the static method to get an array of your LAN computers...
var localComputers = NetworkComputer.GetLocalNetwork();
Nazim was correct. And krowe2's reply is factually incorrect. Switches absolutely forward broadcast traffic. You can send a ping to the subnet's broadcast address under the following conditions.
1.a) You are on the same subnet.
1.b) the gateway allows for IP direct broadcast
2.a) The subnet is not part of a fabric network.
2.b) If the subnet is part of a fabric, broadcast traffic is allowed on the subnet.
In about 80% of networks (and about 99.99% of networks using 192.168.1.1 as a gateway) this will work. I'm a network engineer and I do this all the time.
You CAN NOT rely on ICMP (ping) responses to validate the existence of a device on a network. The problem is that no device is required to listen to any traffic. Not ping, not SNMP, not NetBios. The only real way to be sure is to look at the ARP table.
You have to send out any kind of traffic to every IP in the subnet and look at your own ARP table. Because no device can get any traffic until resolve the MAC address of the IP on the local subnet. So before a device decides if it's going to listen to traffic or not, it has to respond to an ARP request. Your device then caches this in it's ARP table and can send frames with the right destination MAC to the other device.
On a Windows PC, the command line command is 'arp -a'. Linux is 'arp -n' if I recall correctly.
You could ping the adress range and note if a host responded. Of course, this will require the host to respond to the ping packets.
namespace WindowsFormsApplication1
{
class WifiInformation
{
static CountdownEvent countdown;
static int upCount = 0;
static object lockObj = new object();
const bool resolveNames = true;
static void Main(string[] args)
{
string ipBase = getIPAddress();
string[] ipParts = ipBase.Split('.');
ipBase = ipParts[0] + "." + ipParts[1] + "." + ipParts[2] + ".";
for (int i = 1; i < 255; i++)
{
string ip = ipBase + i.ToString();
Ping p = new Ping();
p.PingCompleted += new PingCompletedEventHandler(p_PingCompleted);
p.SendAsync(ip, 100, ip);
}
Console.ReadLine();
}
static void p_PingCompleted(object sender, PingCompletedEventArgs e)
{
string ip = (string)e.UserState;
if (e.Reply != null && e.Reply.Status == IPStatus.Success)
{
if (resolveNames)
{
string name;
try
{
IPHostEntry hostEntry = Dns.GetHostEntry(ip);
name = hostEntry.HostName;
}
catch (SocketException ex)
{
name = "?";
}
Console.WriteLine("{0} ({1}) is up: ({2} ms)", ip, name, e.Reply.RoundtripTime);
}
else
{
Console.WriteLine("{0} is up: ({1} ms)", ip, e.Reply.RoundtripTime);
}
lock (lockObj)
{
upCount++;
}
}
else if (e.Reply == null)
{
Console.WriteLine("Pinging {0} failed. (Null Reply object?)", ip);
}
}
public static string getIPAddress()
{
IPHostEntry host;
string localIP = "";
host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
localIP = ip.ToString();
}
}
return localIP;
}
}
}
Instead of arranging a wild ping-party, you could possibly (I really don't know exactly!) use NetBIOS (request the netbios nametable somehow?) http://technet.microsoft.com/en-us/library/cc757216%28WS.10%29.aspx. Or why not ask your DHCP server?
Ping to the global broadcast ip address (192.168.1.255)
Normally we will get the reply from all the host connected to the LAN.. Or if you have any particular network for the lan, ping to that networks broadcast id (i.e the last ip address in that range ).
Then you can know all the ip address connected to the host in lan.