Monitor continuosly if device is connected over IP - c#

I have an electronic device which is connected to the computer over LAN. I have it's SDK to communicate with it.
Before communicating with the device it must be connected and registered with code provided in SDK. That's all fine.
My win application connects and registers the machine when the application starts up, but the problem is if the electronic device is SWITCHED OFF and then SWITCHED ON, the application must again connect and register the device.
So the question is how to continuously monitor if the device is connected over IP (something like PINGING it via C# code).
So one problem while constantly PINGing the device is that I must run it on separate thread, so that it doesn't affect my actual application. Another good solution would be if I get some piece code which fires event when the device is disconnected over IP.
Thanks for help.
Regards,
EDIT 1: Some piece of code which I use to connect using SDK
bool connected;
connected = axCZKEM1.Connect_Net("192.168.1.201", "4370");
bool registered;
registered = axCZKEM1.RegEvent(1, 65535);
EDIT 2: I am trying the method from answer by sa_ddam213, but I never get a ping failure. Also, it makes my PC run slow. What error am I making ?
while (true)
{
Ping ping = new Ping();
ping.PingCompleted += (sender, e) =>
{
if(e.Reply.Status != IPStatus.Success)
{
connected=false;
registered=false;
while(connected && registered)
{
connected = axCZKEM1.Connect_Net("192.168.1.201", 4370);
registered = axCZKEM1.RegEvent(1, 65535);
}
}
};
ping.Send("192.168.1.201", 3000);
}

You could Ping using c#,
PingReply reply = new Ping().Send("127.0.0.1");
if (reply.Status == IPStatus.Success)
{
// yay
}
Async method:
Ping ping = new Ping();
ping.PingCompleted += (sender, e) =>
{
if (e.Reply.Status == IPStatus.Success)
{
// yay
}
};
ping.SendAsync("127.0.0.1", 3000, null);

Related

PingReply is null when using SendAsync

I am building a server selection screen and have a bunch of IP addresses that need to be pinged in order to know the remote hosts are reachable and to establish a TCP connection afterwards to request their data (like connected playerCount and MOTD, think of Minecraft Multiplayer Selection screen, you don't connect to the game, only requesting data from the endpoint).
The problem is that Ping is always unsuccessful, because the PingReply is null.
For generic use cases, I have wrapped the call with an event that gets fired when the Ping Reply is received back to the sender.
public static async void PingNET(string address, int timeOutMs, System.Action<PingReply> onCompleted)
{
await Task.Run(() => { //to continue unity main thread, start new thread
AutoResetEvent waiter = new AutoResetEvent(false);
var pingSender = new System.Net.NetworkInformation.Ping ();
// call handler when PingCompleted event is raised
pingSender.PingCompleted += (sender, e) =>
{
Debug.LogError ("Error and reply is always null! See: Error is null?: "
+ (e.Error == null) + " - Reply is null?: " + (e.Reply == null));
// If the operation was canceled, display a message to the user.
if (e.Cancelled) {
Debug.LogWarning("Ping canceled.");
}
// If an error occurred, display the exception to the user.
if (e.Error != null) {
Debug.LogError ("Ping failed:" + e.Error.ToString ());
}
if(onCompleted != null)
onCompleted(e.Reply);
};
// Send the ping asynchronously (uses internal new thread,
// so program does not freeze until reply received)
pingSender.SendAsync(address, timeOutMs, waiter);
});
}
Unity Test Runner Unit Test:
[Test]
public void PingTest(){
List<string> addresses = new List<string>(){
"127.0.0.1", "localhost", "www.stackoverflow.com", "www.google.com"
};
for (int i = 0; i < addresses.Count; i++)
{
Ping(addresses[i]);
}
}
private void Ping(string address){
NetworkUtils.PingNET(address, 10000, new System.Action<PingReply>((PingReply reply) => {
if (reply != null && reply.Status == IPStatus.Success)
{
Debug.Log($"Address: {reply.Address.ToString()}");
Debug.Log($"RoundTrip time: {reply.RoundtripTime}");
}
else //this gets called obviously
{
Debug.LogError("PING REPLY ERROR " + reply?.Status);
}
}));
}
Side Info: (Not directly tied to the question)
The reason why I use Ping in the first place is to prevent freeze (deadlock) on the client when the server goes offline while the connection is still tied to it and requesting data to the now unavailable remote host endpoint of the server. I could notify all connected clients that the server is shutting down, but this of course will not work when the server immediately lost connection to the internet.
So all in all, when the ping fails, it should handle in the UI logic to display the server is unreachable. Otherwise if it was successful, a TCP connection to the server is created to send a request. The server that listens on the same port sends a response with the data (playerCount, MOTD, etc.). After that, the client deseralizes the byte array to the datatypes and fires an event, which is subscribed by the UI to gather the deserealized data and display those.
The sending/receiving part with UI already works, just the ping not.
Is this process overcomplicated? Let me know if it could be simplified.
Any help is greatly appreciated.

IpMulticast Stops Working after network is lost and then reconnects after 10-15 mins

I am working on a c# based application which is sending messages continuously using Multi-casting. Every thing works fine. The clients at thereceiving end receives messages continuously till the network is disconnected. But when I reconnect the network the client machines on the same network don't receive any messages till I collect all the messages on the same machine via receiving code.
Send Code:
using (UdpClient udpclient = new UdpClient())
{
IPAddress multicastaddress = IPAddress.Parse("239.0.0.222");
try
{
udpclient.ExclusiveAddressUse = false;
udpclient.MulticastLoopback = false;
udpclient.JoinMulticastGroup(multicastaddress);
IPEndPoint remoteep = new IPEndPoint(multicastaddress, 8191);
int j = udpclient.Send(byteBuffer, byteBuffer.Length, remoteep);
}
catch (Exception e)
{
udpclient.DropMulticastGroup(multicastaddress);
udpclient.Close();
}
finally
{
udpclient.DropMulticastGroup(multicastaddress);
udpclient.Close();
}
});
Receive Code:
var udpClientDispose = new UdpClient(_settingsViewModel.SyncPort);
var ipEndPoint = new IPEndPoint(IPAddress.Any, 8191);
IPAddress multicastaddress = IPAddress.Parse("239.0.0.222");
udpClientDispose.JoinMulticastGroup(multicastaddress, "192.168.0.12");
var timeElapsedSinceMasterMessageReceived = new Stopwatch();
Stopwatch sw = new Stopwatch();
sw.Start();
while (sw.ElapsedMilliseconds < 5000)
{
udpClientDispose.Receive(ref ipEndPoint);
}
udpClientDispose.Close();`
It Seems like all messages are getting collected at my system and there is a network jam on the particular multicast address i.e "239.0.0.222". As if I try to change the address it works but not again on "239.0.0.222".
Anyone knows the exact reason why is this happening and any valid solution to this.
When you say "network is disconnected", I'm going to assume you disable the NIC or physically unplug the wire.
If you subscribe to a multicast group, the NIC driver is instructed to listen to traffic from specific MAC addresses. When the link goes down or the NIC is disabled, the NIC driver will stop to listen to that multicast group and you will have to resubscribe manually.
You can use the NetworkInformation class to subscribe to event information if a NIC goes up/down and use that to resubscribe accordingly.

C# - Socket cannot bind on new ip after changing it by control panel

I discovered some problems by calling the "Bind(IPEndPoint)" method on a socket instance as soon as an adapter changes it's ip address.
Questions:
Why is the new ip not available for about the first 4 seconds after changing it?
If it is expected to behave like this, how to avoid to provocate exceptions while waiting to get the ip available finally?
Do i have to change the socket binding ip in order to receive incoming connections after network adapter gets a new ip?
For reproduction, I appended the code on bottom. Run it, and while running it, change the ip address of the one network adapter displayed in the first output line.
Short description:
I register on "NetworkChange.NetworkAddressChanged". Now I change my IP address using windows, which fires the NetworkAddressChanged event. There, the socket listening on the old local endpoint ip, will be disposed and replaced by a new socket listening on the new local endpoint ip. This seems to work, but with a little delay around 4 seconds. Within those 4 seconds, the method "Bind" throws an SocketException with SocketErrorCode = AddressNotAvailable. What is going wrong there?
Simplified Code:
class Program {
private static Socket socket;
private static IPEndPoint localEP;
private static NetworkInterface niEth;
static void Main(string[] args) {
localEP = new IPEndPoint(IPAddress.Any, 12345);
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
RefreshNetworkInterfaceIP();
while (true) Thread.Sleep(100);
}
private static void NetworkChange_NetworkAddressChanged(object sender, EventArgs e) {
RefreshNetworkInterfaceIP();
}
private static void RefreshNetworkInterfaceIP() {
niEth = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(IsUsableInterface);
Console.WriteLine("Using \"{0}\" as interface!", niEth.Name);
IPAddress newIP = niEth.GetIPProperties().UnicastAddresses.FirstOrDefault(x => x.Address.AddressFamily == AddressFamily.InterNetwork).Address;
// It looks like the new IPAddress is properly set, but Bind still refuses to use this ip...
if (!localEP.Address.Equals(newIP)) {
UnbindSocket();
localEP.Address = newIP;
BindSocket();
}
}
private static bool IsUsableInterface(NetworkInterface ni) {
return ni != null
&& ni.OperationalStatus == OperationalStatus.Up
&& (
ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet
|| ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)
&& ni.GetIPProperties().UnicastAddresses.Any(x => x.Address.AddressFamily == AddressFamily.InterNetwork);
}
private static void BindSocket() {
if (socket != null) UnbindSocket();
socket = new Socket(localEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
do { // This is the waiting workaround.
try { socket.Bind(localEP); } catch (SocketException e) {
if (e.SocketErrorCode == SocketError.AddressNotAvailable) {
Console.WriteLine("The new IP is not ready, waiting a sec...");
Thread.Sleep(1000);
}
}
} while (!socket.IsBound);
socket.Listen(1000);
Console.WriteLine("Socket now listens on: {0}", socket.LocalEndPoint);
}
private static void UnbindSocket() {
if (socket == null) return;
try { socket.Dispose(); } catch (ObjectDisposedException) { }
socket = null;
}
}
This code snippet actually works fine, and thanks to "CurrPorts", socket is really binding and listening to new IP. Even after a call to GC after "socket = null", same behavior.
Note: The surrounding mechanism of this code snippet can now successfully handle following situations:
Network adapters: Reaction on adding/removing adapters of any kind, even the invisible ones (isatap, ...)
WiFi: On/Off by Airplane-Mode, discrete switch and software/driver activation/deactivation/reset
RJ45: Cable out/in, software/driver activation/deactivation/reset
In those cases, the mechanism around that socket knows what it is doing, it is even waiting on isatab and tap-adapters to get their addresses to use them simultaneously.
The only thing is: Windows Network Discovery, triggered by IP address change (tested IPv4 only), which shows up the new ip in "NetworkInterface" but refuses to use it. If IPv6 struggles the same way IPv4 does, I have to find a proper solution for 2 problems except the one I thought it was the only one :)
I am still working forward to get my Project done (some kind of "Network Service Abstraction Layer" for high reliability), but those kind of problems are really nasty to solve and work with...
I would be very happy if someone can point me to the right direction to either wait precisely for binding the socket or to avoid exceptions while trying to bind to that new ip.
Thanks in advance, GK

Listening for an Ethernet Cable Unplugging Event for a TCP Server Application

I have a C# TCP server application. I detect disconnections of TCP clients when they disconnect from server but how can I detect a cable unplug event? When I unplug the ethernet cable I can't detect the disconnection.
You might want to apply "pinging" functionality, that will fail if there is TCP connection lose. Use this code to add extension method to Socket:
using System.Net.Sockets;
namespace Server.Sockets {
public static class SocketExtensions {
public static bool IsConnected(this Socket socket) {
try {
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
} catch(SocketException) {
return false;
}
}
}
}
Method will return false if there is no connection available. It should work to check if there is or no connection even if you had no SocketExceptions on Reveice / Send methods.
Bear in mind that if you had exception that had error message that is related to connection lose, then you don't need check for connection anymore.
This method is meant to be used when socket is looks like connected but might be not like in your case.
Usage:
if (!socket.IsConnected()) {
/* socket is disconnected */
}
Try the NetworkAvailabilityChanged event.
I found this method here. It checks the different states of the connection and signals a disconnect. But does not detect an unplugged cable. After a further search and trial and error this is how I solved it finally.
As the Socket parameter I use on the server side the client socket from the accepted connection and on the client side the client that connected to the server.
public bool IsConnected(Socket socket)
{
try
{
// this checks whether the cable is still connected
// and the partner pc is reachable
Ping p = new Ping();
if (p.Send(this.PartnerName).Status != IPStatus.Success)
{
// you could also raise an event here to inform the user
Debug.WriteLine("Cable disconnected!");
return false;
}
// if the program on the other side went down at this point
// the client or server will know after the failed ping
if (!socket.Connected)
{
return false;
}
// this part would check whether the socket is readable it reliably
// detected if the client or server on the other connection site went offline
// I used this part before I tried the Ping, now it becomes obsolete
// return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException) { return false; }
}
This problem can also be resolved by setting the KeepAlive socket option like this:
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.SetKeepAliveValues(new SocketExtensions.KeepAliveValues
{
Enabled = true,
KeepAliveTimeMilliseconds = 9000,
KeepAliveIntervalMilliseconds = 1000
});
These options can be tweaked to set how often checks are done to ensure the connection is valid. The sending of the Tcp KeepAlive will trigger the socket itself to detect the disconnect of the network cable.

Can't make TCP client code work without USB cable attached

I'm having a bit of trouble in getting a very simple TCP client working on my HTC Titan w/ Windows Phone 7.5.
When the USB cable is attached to the phone, the TCP client works like a charm, but as soon as the cable is unplugged, the client is unable to connect to a TCP server running on my development machine. The devices are on the same network and I'm using the explicit IP-address of my desktop machine to connect, so there's no name resolution going on afaik.
Here's the code I use. Most of it was taken from the Sockets samples on MSDN (can't seem to find the link now though).
private Socket _sock = null;
private ManualResetEvent _done = new ManualResetEvent(false);
private const int TIMEOUT = 5000;
//connect to server
public string Connect(string ip, int port) {
string result = string.Empty;
var host = new IPEndpoint(IPAddress.Parse(ip), port);
_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_sock.SetNetworkRequirement(NetworkSelectionCharacteristics.NonCellular);
var args = new SocketAsyncEventArgs();
args.RemoteEndPoint = host;
args.Completed += new EventHandler((s,e) => {
result = e.SocketError.ToString();
_done.Set();
});
_done.Reset();
_sock.ConnectAsync(args);
_done.WaitOne(TIMEOUT);
return result;
}
//send message
public string Send(string msg) {
string response = "Operation timeout";
if (_sock != null) {
var args= new SocketAsyncEventArgs();
args.RemoteEndPoint = _sock.RemoteEndPoint;
args.Completed += new EventHandler(s, e) => {
response = e.SocketError.ToString();
_done.Set();
});
var payload = Encoding.UTF8.GetBytes(data);
args.SetBuffer(payload, 0, payload.Length);
_done.Reset();
_sock.SendAsync(args);
_done.WaitOne(TIMEOUT);
}
return response;
}
//receive message
public string Receive() {
string response = "Operation timeout";
if (_sock != null) {
var args= new SocketAsyncEventArgs();
args.RemoteEndPoint = _sock.RemoteEndPoint;
args.SetBuffer(new Byte[MAX_BUFSIZE], 0, MAX_BUFSIZE);
args.Completed += new EventHandler((s,e) => {
if (e.SocketError == SocketError.Success) {
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
}
else {
response = e.SocketError.ToString();
}
_done.Set();
});
_done.Reset();
_sock.ReceiveAsync(args);
_done.WaitOne(TIMEOUT);
}
return response;
}
The code is then simply used like:
Connect(...);
Send(...);
Receive(...);
//and then close the socket
As I said before, the code works like a charm when the device is attached to my development machine. When the cable is unplugged, the connection phase just times out (regardless of the timeout interval I should say).
Also, the manifest contains the ID_CAP_NETWORKING capability which as I understand it should give the app permission to access the network.
Any ideas?
EDIT:
I discovered that switching to UDP communication works like a charm. Which means that the problem is that for some reason, the phone is unable to set up a persistant TCP connection to my dev machine. This is getting stranger by the minute.
Do you have a wireless ap nearby on which your phone is connected? because when you plug it in the pc it uses the pc's network connection.
You should check the IP address that you have on both the phone (from your code) and on the PC (which it looks like you've already found using ipconfig in your command prompt).
These should be in the same IP address range, and so start with the same digits (for IPv4, probably something link 192.168.0.*).
If this all matches up check your wireless router hasn't enabled a security setting which means that it doesn't allow TCP traffic from your phone to your PC.
If this is a consumer router you manage this should be fairly simple to verify (and potentially fix). If not, you're probably stuck...

Categories