What's the fastest method to check SQL server availability? - c#

What's the best method to check if SQL server exists or not?
I'm trying Microsoft.SqlServer.Management.Smo.Server.PingSqlServerVersion()
and it works fine if server exists and available.
But it kinda pretty slow, if there is no such a server.
Is there any fast enough method to check without even defining user credentials (only the server name), if a server exists?
What do you recommend to use?

You could still use Microsoft.SqlServer.Management.Smo.Server.PingSqlServerVersion() but use it asynchronously. e.g. you could call it via a BackWorker class. The DoWork event would call Microsoft.SqlServer.Management.Smo.Server.PingSqlServerVersion(). The RunWorkerCompleted would just set a boolean variable to true. THat way you could fire it off, wait however long you wanted, check the boolean value and if it was not true then you would know that the SQL server had not responded yet and you could cancel the BackgroundWorker.

You could just use TcpClient class to query the server and check if a specific port is open, could be something like this:
using System.Net;
using System.Net.Sockets;
public bool CheckServerAvailablity(string serverIPAddress, int port)
{
try
{
IPHostEntry ipHostEntry = Dns.Resolve(serverIPAddress);
IPAddress ipAddress = ipHostEntry.AddressList[0];
TcpClient TcpClient = new TcpClient();
TcpClient.Connect(ipAddress , port);
TcpClient.Close();
return true;
}
catch
{
return false;
}
}

You could try and open a tcp socket to port 1433 (default sql port) with a short timeout and see if it responds.
This requires the SQL server to have the TCP/IP protocol enabled.

To add to Mikael's, you could also ping the host first, as that will respond the quickest if the server is down.
Of course, this all assumes that you are trying to get to a remote server over TCP/IP.

After using Ben Robinson's answer I came up with this and it works good for me.
I was using the connection string to open and then close a connection in a try block but when I ran on Windows 8.1 the exception was never caught and the program crashed.
public unsafe bool OdbcConnectionTest(string sConnectionString
, out int actualTimeMs)
{
DateTime dtme = DateTime.Now;
OdbcConnectionStringBuilder con;
Microsoft.SqlServer.Management.Smo.Server svr;
Microsoft.SqlServer.Management.Common.ServerVersion sVer;
Microsoft.SqlServer.Management.Smo.Database db;
try
{
con = new System.Data.Odbc.OdbcConnectionStringBuilder(sConnectionString);
object sServer;
if (con.TryGetValue("server", out sServer))
{
svr = new Microsoft.SqlServer.Management.Smo.Server((string)sServer);
if (svr != null)
{
sVer = svr.PingSqlServerVersion((string)sServer);
if (sVer != null)
{
object sDb;
if (con.TryGetValue("database", out sDb))
{
if (!String.IsNullOrWhiteSpace((string)sDb))
{
db = svr.Databases[(string)sDb];
if (db != null && db.IsAccessible)
{
TimeSpan ts = DateTime.Now - dtme;
actualTimeMs = (int)ts.TotalMilliseconds;
return true;
}
}
}
}
}
}
}
catch
{
actualTimeMs = -1;
return false;
}
actualTimeMs = -1;
return false;
}

Related

Quickfix/n - No event for connection timeout or host not found?

So I have a project where I need to create failover between two FIX quote hosts in case of failure.
The FixApplication (IApplication) OnLogout() is nice to hook an event to when a socket is dropped or you are logged out. This is simple. But this only works if the socket connection was successful to start off with.
If you start up the application and the host is down, no method is actually called for this anywhere. Not in IApplication, nor in the socket IInitiator. No error is thrown anywhere either, the QuickFix initiator will simply just silently retry.
I am using a Timer with a callback right now to manually poll every so often and check if Initiator IsLoggedOn() is false. Then triggering a failover.
But this is really clunky and not elegant.
Is there any other event or method I can hook into to receive the notice for socket network failures BEFORE a network connection and session is established successfully?
Thanks!
Timer t = new Timer(5000)
t.Elapsed += CheckSocketConnected;
private void CheckSocketConnected(object source, ElapsedEventArgs e)
{
var connected = socketInitiator.IsLoggedOn;
if (!connected)
{
SwitchToAlternateProvider();
}
}
Well, after realising the limitation of the QuickFix/N component, I would never receive any feedback from this library if the host was down.
My resolution was to just simply use the following piece of code to check if socket was open before starting the connection in QuickFix/n
bool IsPortOpen(string host, int port, TimeSpan timeout)
{
try
{
using(var client = new TcpClient())
{
var result = client.BeginConnect(host, port, null, null);
var success = result.AsyncWaitHandle.WaitOne(timeout);
if (!success)
{
return false;
}
client.EndConnect(result);
}
}
catch
{
return false;
}
return true;
}

How to reconnect to a socket gracefully

I have a following method that connects to an end point when my program starts
ChannelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var remoteIpAddress = IPAddress.Parse(ChannelIp);
ChannelEndPoint = new IPEndPoint(remoteIpAddress, ChannelPort);
ChannelSocket.Connect(ChannelEndPoint);
I also have a timer that is set to trigger every 60 seconds to call CheckConnectivity, that attempts to send an arbitrary byte array to the end point to make sure that the connection is still alive, and if the send fails, it will attempt to reconnect.
public bool CheckConnectivity(bool isReconnect)
{
if (ChannelSocket != null)
{
var blockingState = ChannelSocket.Blocking;
try
{
var tmp = new byte[] { 0 };
ChannelSocket.Blocking = false;
ChannelSocket.Send(tmp);
}
catch (SocketException e)
{
try
{
ReconnectChannel();
}
catch (Exception ex)
{
return false;
}
}
}
else
{
ConnectivityLog.Warn(string.Format("{0}:{1} is null!", ChannelIp, ChannelPort));
return false;
}
return true;
}
private void ReconnectChannel()
{
try
{
ChannelSocket.Shutdown(SocketShutdown.Both);
ChannelSocket.Disconnect(true);
ChannelSocket.Close();
}
catch (Exception ex)
{
ConnectivityLog.Error(ex);
}
ChannelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var remoteIpAddress = IPAddress.Parse(ChannelIp);
ChannelEndPoint = new IPEndPoint(remoteIpAddress, ChannelPort);
ChannelSocket.Connect(ChannelEndPoint);
Thread.Sleep(1000);
if (ChannelSocket.Connected)
{
ConnectivityLog.Info(string.Format("{0}:{1} is reconnected!", ChannelIp, ChannelPort));
}
else
{
ConnectivityLog.Warn(string.Format("{0}:{1} failed to reconnect!", ChannelIp, ChannelPort));
}
}
So how I'd test the above, is to physically unplug the LAN cable from my ethernet device, allowing my code to attempt to reconnect (which fails obviously) and reconnect back the LAN cable.
However, even after reconnecting the LAN cable (able to ping), ChannelSocket.Connect(ChannelEndPoint) in my Reconnect method always throws this error
No connection could be made because the target machine actively refused it 192.168.168.160:4001
If I were to restart my whole application, it connects successfully. How can I tweak my reconnect method such that I don't have to restart my application to reconnect back to my Ethernet device?
If an application closes a TCP/IP port, the protocol dictates that the port stays in TIME_WAIT state for a certain duration (default of 240 seconds on a windows machine).
See following for references -
http://en.wikipedia.org/wiki/Transmission_Control_Protocol
http://support.microsoft.com/kb/137984
http://www.pctools.com/guides/registry/detail/878/
What this means for your scenario - is that you cannot expect to close (willingly or unwillingly) and re-open a port within a short period of time (even several seconds). Despite some registry tweaks which you'd find on internet.. the port will be un-available for any app on windows, for a minimum of 30 seconds. (Again, default is 240 seconds)
Your options - here are limited...
From the documentation at http://msdn.microsoft.com/en-us/library/4xzx2d41(v=vs.110).aspx -
"If the socket has been previously disconnected, then you cannot use this (Connect) method to restore the connection. Use one of the asynchronous BeginConnect methods to reconnect. This is a limitation of the underlying provider."
The reason why documentation suggests that BeginConnect must be used is what I mentioned above.. It simply doesn't expect to be able to establish the connection right away.. and hence the only option is to make the call asynchronously, and while you wait for the connection to get established in several minutes, do expect and plan for it to fail. Essentially, likely not an ideal option.
If the long wait and uncertainty is not acceptable, then your other option is to somehow negotiate a different port between the client and server. (For example, in theory you could use UDP, which is connectionless, to negotiate the new TCP port you'd re-establish the connection on). Communication using UDP, in theory of course, itself is not guaranteed by design. But should work most of the times (Today, networking in typical org is not that flaky / unreliable). Subjective to scenario / opinion, perhaps better than option 1, but more work and smaller but finite chance of not working.
As suggested in one of the comments, this is where application layer protocols like http and http services have an advantage. Use them, instead of low level sockets, if you can.
If acceptable, this is the best option to go with.
(PS - FYI - For HTTP, there is a lot of special handling built into OS, including windows - For example, there is a dedicated driver Http.sys, specially for dealing with multiple apps trying to listen on same port 80 etc.. The details here are a topic for another time.. point is, there is lots of goodness and hard work done for you, when it comes to HTTP)
Maybe you should switch to a higher abstraction class, which better deals with all these nifty little details?
I'm going to use for these network connections the TcpListener and TcpClient classes. The usage of these classes is quite easy:
The client side:
public void GetInformationAsync(IPAddress ipAddress)
{
_Log.Info("Start retrieving informations from address " + ipAddress + ".");
var tcpClient = new TcpClient();
tcpClient.BeginConnect(ipAddress, _PortNumber, OnTcpClientConnected, tcpClient);
}
private void OnTcpClientConnected(IAsyncResult asyncResult)
{
try
{
using (var tcpClient = (TcpClient)asyncResult.AsyncState)
{
tcpClient.EndConnect(asyncResult);
var ipAddress = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address;
var stream = tcpClient.GetStream();
stream.ReadTimeout = 5000;
_Log.Debug("Connection established to " + ipAddress + ".");
var formatter = new BinaryFormatter();
var information = (MyInformation)formatter.Deserialize(stream);
_Log.Info("Successfully retrieved information from address " + ipAddress + ".");
InformationAvailable.FireEvent(this, new InformationEventArgs(information));
}
}
catch (Exception ex)
{
_Log.Error("Error in retrieving informations.", ex);
return;
}
}
The server side:
public void Start()
{
ThrowIfDisposed();
if (_TcpServer != null;)
_TcpServer.Stop();
_TcpServer = new TcpListener(IPAddress.Any, _PortNumber);
_TcpServer.Start();
_TcpServer.BeginAcceptTcpClient(OnClientConnected, _TcpServer);
_Log.Info("Start listening for incoming connections on " + _TcpServer.LocalEndpoint + ".");
}
private void OnClientConnected(IAsyncResult asyncResult)
{
var tcpServer = (TcpListener)asyncResult.AsyncState;
IPAddress address = IPAddress.None;
try
{
if (tcpServer.Server != null
&& tcpServer.Server.IsBound)
tcpServer.BeginAcceptTcpClient(OnClientConnected, tcpServer);
using (var client = tcpServer.EndAcceptTcpClient(asyncResult))
{
address = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
_Log.Debug("Client connected from address " + address + ".");
var formatter = new BinaryFormatter();
var informations = new MyInformation()
{
// Initialize properties with desired values.
};
var stream = client.GetStream();
formatter.Serialize(stream, description);
_Log.Debug("Sucessfully serialized information into network stream.");
}
}
catch (ObjectDisposedException)
{
// This normally happens, when the server will be stopped
// and their exists no other reliable way to check this state
// before calling EndAcceptTcpClient().
}
catch (Exception ex)
{
_Log.Error(String.Format("Cannot send instance information to {0}.", address), ex);
}
}
This code works and doesn't make any problems with a lost connection on the client side. If you have a lost connection on the server side you have to re-establish the listener, but that's another story.
In ReconnectChannel just dispose the ChannelSocket object.
try
{
`//ChannelSocket.Shutdown(SocketShutdown.Both);
//ChannelSocket.Disconnect(true);
//ChannelSocket.Close();
ChannelSocket.Dispose();`
}
This is working for me. Let me know if it doesn't work for you.

C# TCPClient/Socket writing not throwing exception

I have many printers I am trying to connect to over tcp connections. I am trying to verify that my TcpClient is still connected to update a GUI. I am trying to write to a socket to make sure its still connected. I get no exception even if the cable is unplugged I tried all of the suggestions here MSDN_Fourm
I am receiving the expected exception after I try to check the printer statuses
psudo-code
client is a TCPClient that has been connected previously
private bool FuntionPsudo(){
try{
if(client.Connected){
byte[] buf = new byte[1];
client.Client.Send(buf, 0,0);
client.GetStream().Write(buf,0,0);
if(client.Client.Receive(buf,SocketFlags.Peek)==0)
return false;
return true;
}
}
catch(Exception){
return false;
}
return false;
}
FuntionPsudo returns: true
cable unplugged
FuntionPsudo returns: true
FuntionPsudo returns: true
check printer status
FuntionPsudo returns: false
Thanks in advance for any help on why this might be happening and/or how to fix it
After several failed attempts I realised 'unplug-the-cable' type of connecting detection isn't that easy. At the same time I found that there are a couple of tricks you can do to check if the server has closed the connection, all without needing to send hearbeat kind of messages.
Here is what I came up with that I could say it works most of the time (especially with cable disconnects it's not easy to figure out if connection is still up)
static class SocketUtils
{
public static bool IsConnected(this Socket socket)
{
return IsSocketConnected(socket) && IsNetworkConnected(socket);
}
public static void KeepAlive(this Socket socket, int pollSeconds)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
SetIOControlKeepAlive(socket, (uint)(pollSeconds * 1000), 1);
}
static bool IsNetworkConnected(this Socket socket)
{
try
{
return socket.Send(new byte[0]) == 0;
}
catch (SocketException) { return false; }
}
static bool IsSocketConnected(this Socket socket)
{
try
{
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException) { return false; }
}
static void SetIOControlKeepAlive(Socket socket, uint time, uint interval)
{
var sizeOfUint = Marshal.SizeOf(time);
var inOptionValues = new byte[sizeOfUint * 3];
BitConverter.GetBytes((uint)(time == 0 ? 0UL : 1UL)).CopyTo(inOptionValues, 0);
BitConverter.GetBytes(time).CopyTo(inOptionValues, sizeOfUint);
BitConverter.GetBytes(interval).CopyTo(inOptionValues, sizeOfUint * 2);
socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
}
}
Here is how you can use it:
var tcpClient = new TcpClient();
tcpClient.Connect("192.168.2.20", 3000);
// set this to a low value to detect cable disconnects early
tcpClient.Client.KeepAlive(30); // 30 seconds
Console.WriteLine("Connected..");
while (true)
{
Thread.Sleep(500);
Console.WriteLine(tcpClient.Client.IsConnected());
}
I must add that I shamelessly copied some code from Samuel's answer about checking client disconnects and Greg Dean's answer about setting keep-alive on the socket, so some credit should go to them as well ;)
You can only tell whether you are still connected or not by sending something and receiving something back. Just pushing bytes out into the network always works even if they go into a black hole. The Connected property is unreliable and almost all code using it is wrong.
Send something to the printer and receive a reply. Or, create a new connection (which internally will send and receive TCP control packets without data).
When dealing with transport layers like the TCP protocol you need to use it like a 'Walkie-Talkie'. You need to decide when and for how long to talk. In other words the communication breaks down when both parties talk or listen at the same time.
Here is an example from the book C# in a Nutshell:
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
class TcpDemo
{
static void Main()
{
new Thread(Server).Start(); // Run server method concurrently.
Thread.Sleep(500); // Give server time to start.
Client();
}
static void Client()
{
using (TcpClient client = new TcpClient("localhost", 51111 ))
using(NetworkStream n = client.GetStream())
{
BinaryWriter w = new BinaryWriter(n);
w.Write("Hello");
w.Flush();
Console.WriteLine(new BinaryReader(n).ReadString());
}
}
static void Server()
{
TcpListener listener = new TcpListener(IPAddress.Any, 51111);
listener.Start();
using(TcpClient c = listener.AcceptTcpClient())
using(NetworkStream n = c.GetStream())
{
string msg = new BinaryReader(n).ReadString();
BinaryWriter w = new BinaryWriter(n);
w.Write(msg + " right back!");
w.Flush();
}
listener.Stop();
}
}
I have same this propblem for reconnect.
I write server in java and client in c# (unity)
java-java throw exception ok
java-c# : both of them throw exception in some case.
I have the best way for perfomance server
I resolve by the way : write jar client and use ikvm export to dll (copy jar to ikvm/bin). Create library in c# and reference dll + ikvm.core.dll + .../manage/unityEngine.dll ==> copy Cshapr/bin/Debug to UnityProJect/Asset
--> it run ok but speed over 37M to build 😭
If you want to have a small client --> network with no reconnect 😅

Check if a port is open

I can't seem to find anything that tells me if a port in my router is open or not.
Is this even possible?
The code I have right now doesn't really seem to work...
private void ScanPort()
{
string hostname = "localhost";
int portno = 9081;
IPAddress ipa = (IPAddress) Dns.GetHostAddresses(hostname)[0];
try
{
System.Net.Sockets.Socket sock =
new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork,
System.Net.Sockets.SocketType.Stream,
System.Net.Sockets.ProtocolType.Tcp);
sock.Connect(ipa, portno);
if (sock.Connected == true) // Port is in use and connection is successful
MessageBox.Show("Port is Closed");
sock.Close();
}
catch (System.Net.Sockets.SocketException ex)
{
if (ex.ErrorCode == 10061) // Port is unused and could not establish connection
MessageBox.Show("Port is Open!");
else
MessageBox.Show(ex.Message);
}
}
Try this:
using(TcpClient tcpClient = new TcpClient())
{
try {
tcpClient.Connect("127.0.0.1", 9081);
Console.WriteLine("Port open");
} catch (Exception) {
Console.WriteLine("Port closed");
}
}
You should probably change 127.0.0.1 to something like 192.168.0.1 or whatever your router's IP address is.
A better solution where you can even specify a timeout:
using System;
using System.Net.Sockets;
// ...
bool IsPortOpen(string host, int port, TimeSpan timeout)
{
try
{
using(var client = new TcpClient())
{
var result = client.BeginConnect(host, port, null, null);
var success = result.AsyncWaitHandle.WaitOne(timeout);
client.EndConnect(result);
return success;
}
}
catch
{
return false;
}
}
And, in F#:
open System
open System.Net.Sockets
let isPortOpen (host: string) (port: int) (timeout: TimeSpan): bool =
try
use client = new TcpClient()
let result = client.BeginConnect(host, port, null, null)
let success = result.AsyncWaitHandle.WaitOne timeout
client.EndConnect result
success
with
| _ -> false
let available = isPortOpen "stackoverflow.com" 80 (TimeSpan.FromSeconds 10.)
printf "Is stackoverflow available? %b" available
There is no way to know if the port is forwarded in your router, except if there is a program listening on that port.
As you may see in the Clinton answer, the .Net class being used is TcpClient and that is because you are using a TCP socket to connect to. That is the way operating systems make connections: using a socket. However, a router just forwards the packets (layer 3 of the OSI Model) in or out. In your case, what your router is doing is called: NAT. It is one public IP shared by a one or more private IPs. That´s why you are making a port forwarding.
There may be a lot of routers in the path of the packets, and you will never know what had happened.
Let´s imagine you are sending a letter in the traditional way. Perhaps you can write in the letter that the receiver must answer, in order to check he/she is there (you and the receiver are the sockets). If you receive an answer you will be sure he/she is there, but if you don´t receive anything you don´t know if the mailman (in your case the router) forgot to deliver the letter, or the receiver hadn´t answered. You would also never know if the mailman has asked a friend to deliver that letter. Moreover, the mailman won´t open the letter in order to know he/she may answer because you are waiting for a reply. All you may do is wait some time to receive the answer. If you don´t receive anything in that period you will assume that the receiver isn´t where you sent the letter. That is a "timeout".
I saw an answer mentioning the nmap software. It´s really a very good and complex soft, but I think it will work in the same way. If there is no app listening in that port, there is no way to know if it is open or not.
Please, let me know if I was clear.
If you're connecting to the loopback adapter — localhost or 127.0.0.1 (there's no place like 127.0.0.1!), you're unlikely to ever go out to the router. The OS is smart enough to recognize that it's a special address. Dunno if that holds true as well if you actually specify your machine's "real" IP address.
See also this question: What is the purpose of the Microsoft Loopback Adapter?
Also note that running traceroute localhost (tracert localhost in Windows) shows that the only network node involved is your own machine. The router is never involved.
Other than BeginConnect you can also use ConnectAsync (added in .NET Framework 4.5 I think?).
TcpClient client = null;
try {
client = new TcpClient();
var task = client.ConnectAsync(host, port);
if (task.Wait(timeout)) {//if fails within timeout, task.Wait still returns true.
if (client.Connected) {
// port reachable
}
else
// connection refused probably
}
else
// timed out
}
catch (Exception ex) {
// connection failed
}
finally {
client.Close();
}
Full project is here because paping refuses to run and I couldn't find another "ping host:port" tool to my likes.
A port forward on the router cannot be tested from inside the LAN, you need to connect from the WAN (internet) side to see if a port forward is working or not.
Several internet sites offer services to check if a port is open:
What's My IP Port Scanner
GRC | ShieldsUP!
If you want to check with your own code, then you need to make sure the TCP/IP connection is rerouted via an external proxy or setup a tunnel. This has nothing to do with your code, it's basic networking 101.
public static bool PortInUse(int port)
{
bool inUse = false;
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint [] ipEndPoints = ipProperties.GetActiveTcpListeners();
foreach(IPEndPoint endPoint in ipEndPoints)
{
if(endPoint.Port == port)
{
inUse = true;
break;
}
}
return inUse;
}
For me, I needed something blocking until the connection to the port is available or after a certain amount of retries. So, I figured out this code:
public bool IsPortOpen(string host, int port, int timeout, int retry)
{
var retryCount = 0;
while (retryCount < retry)
{
if (retryCount > 0)
Thread.Sleep(timeout);
try
{
using (var client = new TcpClient())
{
var result = client.BeginConnect(host, port, null, null);
var success = result.AsyncWaitHandle.WaitOne(timeout);
if (success)
return true;
client.EndConnect(result);
}
}
catch
{
// ignored
}
finally { retryCount++; }
}
return false;
}
Hope this helps!
also you can use ConnectAsync like
public async Task<bool> IsIPAndPortOpen(string hostOrIPAddress, int port, TimeSpan timeOut)
{
try
{
using (var client = new TcpClient())
{
var ct = new CancellationTokenSource(timeOut).Token;
await client.ConnectAsync(hostOrIPAddress, port, ct);
return true;
}
}
catch
{
return false;
}
}
public string GetAvailablePort()
{int startingPort=1000;
string portnumberinformation = string.Empty;
IPEndPoint[] endPoints;
List<int> portArray = new List<int>();
IPGlobalPr`enter code here`operties properties = IPGlobalProperties.GetIPGlobalProperties();`enter code here`
//getting active tcp listners
endPoints = properties.GetActiveTcpListeners();
portArray.AddRange(from n in endPoints
where n.Port >= startingPort
select n.Port);
portArray.Sort();
for (int i = 0; i < portArray.Count; i++)
{
if (check condition)
{
do somting
}
}
return portnumberinformation;
}
If it is Router the simplest way to check it through online services like
Port Checker
Port Forwarding Test
You can also try using telenet to chek wether port is accessible or not
telenet [ip-address] [port]

How to check if TcpClient Connection is closed?

I'm playing around with the TcpClient and I'm trying to figure out how to make the Connected property say false when a connection is dropped.
I tried doing
NetworkStream ns = client.GetStream();
ns.Write(new byte[1], 0, 0);
But it still will not show me if the TcpClient is disconnected. How would you go about this using a TcpClient?
I wouldn't recommend you to try write just for testing the socket. And don't relay on .NET's Connected property either.
If you want to know if the remote end point is still active, you can use TcpConnectionInformation:
TcpClient client = new TcpClient(host, port);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections().Where(x => x.LocalEndPoint.Equals(client.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint)).ToArray();
if (tcpConnections != null && tcpConnections.Length > 0)
{
TcpState stateOfConnection = tcpConnections.First().State;
if (stateOfConnection == TcpState.Established)
{
// Connection is OK
}
else
{
// No active tcp Connection to hostName:port
}
}
client.Close();
See Also:
TcpConnectionInformation on MSDN
IPGlobalProperties on MSDN
Description of TcpState states
Netstat on Wikipedia
And here it is as an extension method on TcpClient.
public static TcpState GetState(this TcpClient tcpClient)
{
var foo = IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpConnections()
.SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint));
return foo != null ? foo.State : TcpState.Unknown;
}
As far as I know/remember there is no way to test if a socket is connected other than reading or writing to it.
I haven't used the TcpClient at all but the Socket class will return 0 from a call to Read if the remote end has been shutdown gracefully.
If the remote end doesn't shutdown gracefully [I think] you get a timeout exception, can't remember the type sorry.
Using code like 'if(socket.Connected) { socket.Write(...) } creates a race condition. You're better off just calling socket.Write and handling the exceptions and/or disconnections.
The solution of Peter Wone and uriel is very nice. But you also need to check on the Remote Endpoint, since you can have multiple open connections to your Local Endpoint.
public static TcpState GetState(this TcpClient tcpClient)
{
var foo = IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpConnections()
.SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint)
&& x.RemoteEndPoint.Equals(tcpClient.Client.RemoteEndPoint)
);
return foo != null ? foo.State : TcpState.Unknown;
}
I have created this function and working for me to check if client is still connected with server.
/// <summary>
/// THIS FUNCTION WILL CHECK IF CLIENT IS STILL CONNECTED WITH SERVER.
/// </summary>
/// <returns>FALSE IF NOT CONNECTED ELSE TRUE</returns>
public bool isClientConnected()
{
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections();
foreach (TcpConnectionInformation c in tcpConnections)
{
TcpState stateOfConnection = c.State;
if (c.LocalEndPoint.Equals(ClientSocket.Client.LocalEndPoint) && c.RemoteEndPoint.Equals(ClientSocket.Client.RemoteEndPoint))
{
if (stateOfConnection == TcpState.Established)
{
return true;
}
else
{
return false;
}
}
}
return false;
}
#uriel's answer works great for me, but I needed to code it in C++/CLI, which was not entirely trivial. Here is the (roughly equivalent) C++/CLI code, with a few robustness checks added in for good measure.
using namespace System::Net::Sockets;
using namespace System::Net::NetworkInformation;
TcpState GetTcpConnectionState(TcpClient ^ tcpClient)
{
TcpState tcpState = TcpState::Unknown;
if (tcpClient != nullptr)
{
// Get all active TCP connections
IPGlobalProperties ^ ipProperties = IPGlobalProperties::GetIPGlobalProperties();
array<TcpConnectionInformation^> ^ tcpConnections = ipProperties->GetActiveTcpConnections();
if ((tcpConnections != nullptr) && (tcpConnections->Length > 0))
{
// Get the end points of the TCP connection in question
EndPoint ^ localEndPoint = tcpClient->Client->LocalEndPoint;
EndPoint ^ remoteEndPoint = tcpClient->Client->RemoteEndPoint;
// Run through all active TCP connections to locate TCP connection in question
for (int i = 0; i < tcpConnections->Length; i++)
{
if ((tcpConnections[i]->LocalEndPoint->Equals(localEndPoint)) && (tcpConnections[i]->RemoteEndPoint->Equals(remoteEndPoint)))
{
// Found active TCP connection in question
tcpState = tcpConnections[i]->State;
break;
}
}
}
}
return tcpState;
}
bool TcpConnected(TcpClient ^ tcpClient)
{
bool bTcpConnected = false;
if (tcpClient != nullptr)
{
if (GetTcpConnectionState(tcpClient) == TcpState::Established)
{
bTcpConnected = true;
}
}
return bTcpConnected;
}
Hopefully this will help somebody.
As of 2019, in a cross-platform and async environment, I use the code below to continuosly check that the TCP channel is open. This check fires e.g. if the ethernet cable is pulled on my Windows machine, or if the Wifi is disabled on my Android device.
private async Task TestConnectionLoop()
{
byte[] buffer = new byte[1];
ArraySegment<byte> arraySegment = new ArraySegment<byte>(buffer, 0, 0);
SocketFlags flags = SocketFlags.None;
while (!_cancellationSource.Token.IsCancellationRequested)
{
try
{
await _soc.SendAsync(arraySegment, flags);
await Task.Delay(500);
}
catch (Exception e)
{
_cancellationSource.Cancel();
// Others can listen to the Cancellation Token or you
// can do other actions here
}
}
}
Please note that I have found GSF.Communication wrapper for System.Net.Sockets.TcpClient to be helpful because it has a CurrentState property that indicates whether the socket is open/connected or closed/disconnected. You can find details on the NuGet package here:
https://github.com/GridProtectionAlliance/gsf
Here is how you could setup a simple TCP socket and test whether it is connected:
GSF.Communication.TcpClient tcpClient;
void TestTcpConnectivity()
{
tcpClient = new GSF.Communication.TcpClient();
string myTCPServer = "localhost";
string myTCPport = "8080";
tcpClient.MaxConnectionAttempts = 5;
tcpClient.ConnectionAttempt += s_client_ConnectionAttempt;
tcpClient.ReceiveDataComplete += s_client_ReceiveDataComplete;
tcpClient.ConnectionException += s_client_ConnectionException;
tcpClient.ConnectionEstablished += s_client_ConnectionEstablished;
tcpClient.ConnectionTerminated += s_client_ConnectionTerminated;
tcpClient.ConnectionString = "Server=" + myTCPServer + ":" + myTCPport;
tcpClient.Initialize();
tcpClient.Connect();
Thread.Sleep(250);
if (tcpClient.CurrentState == ClientState.Connected)
{
Debug.WriteLine("Socket is connected");
// Do more stuff
}
else if (tcpClient.CurrentState == ClientState.Disconnected)
{
Debug.WriteLine(#"Socket didn't connect");
// Do other stuff or try again to connect
}
}
void s_client_ConnectionAttempt(object sender, EventArgs e)
{
Debug.WriteLine("Client is connecting to server.");
}
void s_client_ConnectionException(object sender, EventArgs e)
{
Debug.WriteLine("Client exception - {0}.", e.Argument.Message);
}
void s_client_ConnectionEstablished(object sender, EventArgs e)
{
Debug.WriteLine("Client connected to server.");
}
void s_client_ConnectionTerminated(object sender, EventArgs e)
{
Debug.WriteLine("Client disconnected from server.");
}
void s_client_ReceiveDataComplete(object sender, GSF.EventArgs<byte[], int> e)
{
Debug.WriteLine(string.Format("Received data - {0}.", tcpClient.TextEncoding.GetString(e.Argument1, 0, e.Argument2)));
}
I recommend the code from the answer of the user 'Uriel' above. His code in principle works great:
TcpClient client = new TcpClient(host, port);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections().Where(x => x.LocalEndPoint.Equals(client.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint)).ToArray();
but it has a bug:
IPEndPoint.Equals() is used here to search the retrieved list of TCP connections for the one connection that has the same endpoints as the socket TcpClient.Client of the used TCP client.
The idea and concept are fine, but in real life may fail because of the coexistence of IPv4 and IPv6: Current operating systems like Windows 10 support IPv4 and IPv6, and sockets may be created with IPv6 addresses even if addresses like "100.111.1.251" in the IPv4 format were configured:
// Creation of TCP client:
m_tcpClient = new TcpClient ();
m_tcpClient.Connect ("100.111.1.251", 54321);
// Query of the local and remote IP endpoints in Visual Studio Immediate Window:
?m_tcpClient.Client.LocalEndPoint
{[::ffff:100.111.1.254]:55412}
Address: {::ffff:100.111.1.254}
AddressFamily: InterNetworkV6
Port: 55412
?m_tcpClient.Client.RemoteEndPoint
{[::ffff:100.111.1.251]:54321}
Address: {::ffff:100.111.1.251}
AddressFamily: InterNetworkV6
Port: 54321
// Query of the addresses of the local and remote IP endpoints in Visual Studio Immediate Window:
?((IPEndPoint)m_tcpClient.Client.LocalEndPoint).Address
{::ffff:100.111.1.254}
Address: '((IPEndPoint)m_tcpClient.Client.LocalEndPoint).Address.Address' threw an exception of type 'System.Net.Sockets.SocketException'
AddressFamily: InterNetworkV6
IsIPv4MappedToIPv6: true
IsIPv6LinkLocal: false
IsIPv6Multicast: false
IsIPv6SiteLocal: false
IsIPv6Teredo: false
ScopeId: 0
?((IPEndPoint)m_tcpClient.Client.RemoteEndPoint).Address
{::ffff:100.111.1.251}
Address: '((IPEndPoint)m_tcpClient.Client.RemoteEndPoint).Address.Address' threw an exception of type 'System.Net.Sockets.SocketException'
AddressFamily: InterNetworkV6
IsIPv4MappedToIPv6: true
IsIPv6LinkLocal: false
IsIPv6Multicast: false
IsIPv6SiteLocal: false
IsIPv6Teredo: false
ScopeId: 0
AddressFamily: InterNetworkV6 and IsIPv4MappedToIPv6: true indicate that the IP address in the local IP endpoint is an IPv6 address, although an IPv4 address was used to establish the connection. This obviously is because the socket is created in "dual-mode" or as "dual-stack":
https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses
https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.isipv4mappedtoipv6
https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2
https://www.ibm.com/docs/en/zos/2.2.0?topic=addresses-ipv4-mapped-ipv6
IPGlobalProperties.GetActiveTcpConnections() on the other side seems to always return IPEndPoint objects with IPv4 addresses:
?IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections()[48].LocalEndPoint
{100.111.1.254:55412}
Address: {100.111.1.254}
AddressFamily: InterNetwork
Port: 55412
The consequence is that IPEndPoint.Equals() may return false even if two compared EndPoint objects refer to the same IP endpoint.
The solution for this problem is writing your own Equals() method, like:
public static class EndPointHelper
{
private static readonly AddressFamily[] addressFamilies =
{
AddressFamily.InterNetwork,
AddressFamily.InterNetworkV6
};
public static bool Equals (EndPoint? endPoint1, EndPoint? endPoint2)
{
if (endPoint1 is IPEndPoint ipEndPoint1 &&
endPoint2 is IPEndPoint ipEndPoint2)
{
if (ipEndPoint1.AddressFamily != ipEndPoint2.AddressFamily &&
addressFamilies.Contains(ipEndPoint1.AddressFamily) &&
addressFamilies.Contains(ipEndPoint2.AddressFamily))
{
var ipAddress1AsV6 = ipEndPoint1.Address.MapToIPv6();
var ipAddress2AsV6 = ipEndPoint2.Address.MapToIPv6();
return ipAddress1AsV6.Equals(ipAddress2AsV6)
&& ipEndPoint1.Port.Equals(ipEndPoint2.Port);
}
}
return object.Equals (i_endPoint1, i_endPoint2);
}
}
Furthermore, there is a bug in .NET 5, which makes the whole solution above unusable: IPGlobalProperties.GetActiveTcpConnections() has a memory leak (see https://github.com/dotnet/runtime/issues/64735), which will not be fixed in .NET 5 any more, because it has run out of support. The bug is not present in .NET 6. If you are tied to .NET 5, you will have to work around it by remembering the connection state yourself in a local variable (e.g. EnumState m_cachedState). Set this variable after each related operation, e.g. after a Connect() you would have to set it to EnumState.Connected.
This method of course will not detect when a connection was closed by the other side, so you have to cyclically check if the connection was closed, using this code:
var socket = m_tcpClient.Client;
bool state = socket.Poll (100, SelectMode.SelectRead);
int available = socket.Available;
return state && available == 0 // Condition for externally closed connection. The external close will not be recognized until all received data has been read.
? EnumState.Idle
: m_cachedState;
Try this, it works for me
private void timer1_Tick(object sender, EventArgs e)
{
if (client.Client.Poll(0, SelectMode.SelectRead))
{
if (!client.Connected) sConnected = false;
else
{
byte[] b = new byte[1];
try
{
if (client.Client.Receive(b, SocketFlags.Peek) == 0)
{
// Client disconnected
sConnected = false;
}
}
catch { sConnected = false; }
}
}
if (!sConnected)
{
//--Basically what you want to do afterwards
timer1.Stop();
client.Close();
ReConnect();
}
}
i used Timer because, I wanted to check connection state at regular interval
and not in a LOOP with Listening code [I felt it was slowing the sending-recieving process]
In my case, I was sending some command to a server (running in a virtual machine on the same computer) and waiting for the response. However, if the server stopped unexpectedly while waiting, I did not get any notification. I tried the possibilities proposed by the other posters, but neither did work (it always said that the server is still connected). For me, the only thing that is working is to write 0 bytes to the stream:
var client = new TcpClient();
//... open the client
var stream = client.GetStream();
//... send something to the client
byte[] empty = { 0 };
//wait for response from server
while (client.Available == 0)
{
//throws a SocketException if the connection is closed by the server
stream.Write(empty, 0, 0);
Thread.Sleep(10);
}

Categories