I'm trying to do a retry coding if my client fail to connect to my server. Below is how i do:
In main function:
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
ConnectCallback:
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
_logger.Info("## Connection to server successful at " + strServerIP + ":" + strServerPort);
}
catch (Exception ex)
{
_logger.Info("## Connection to server failed. Retrying...");
Socket client = (Socket)ar.AsyncState;
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(strServerIP), Convert.ToInt32(strServerPort));
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
}
}
I will catch the exception in ConnectCallback when connection fail and do retry.
But I found out that, if it retried 10 times, when server is up, the server will get 10 connection from that same client. If it retry 50 times, when server is up, then server will get 50 connections.
Is my coding something wrong? Seems like everytime it retry, my server will get a new connection.
Without a functioning example it's difficult to know. If this is close to what you are actually doing, I suspect a couple of things are wrong. The Socket object appears to be blocking by default, but something is generating your exception and it may not be what you think it is. First thing to do is only catch the SocketException and then only retry when the exception represents something that might indicate a retry would work. Put in a delay because if it didn't work 1 ms ago, it probably won't work now. Put in a sanity counter so it gives up retrying after so many tries. Examine your protocol to make sure you are sending the server what it expects. Above all Close your sockets.
What I suspect you are seeing is a bunch of Socket connections caused by an exception (which may or may not be related to the sockets). Since you never close them they just build up. I suspect that eventually the GC might kick in and run finalizers on the objects which would then drop their connections. More likely the server would drop the connections. Either way if you aren't explicitly closing your Socket then it will hang around until something times out.
Here is a working example that demonstrates what I think you are asking. Again you need to decide under what conditions you should retry because retrying if anything goes wrong is not good. It may cause your program to constantly churn threads and possibly even connections.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Microsoft.Extensions.Logging;
namespace socketTst {
class Program {
static ILoggerFactory loggerFactory = new LoggerFactory().AddConsole().AddDebug();
static ILogger _logger;
static AutoResetEvent finish = new AutoResetEvent(false);
static String Hostname = "www.google.com";
static int Port = 80;
static int RetryCount = 0;
static void ConnectCallback(IAsyncResult ar) {
_logger.LogInformation($"## ConnectCallback entered");
// Retrieve the socket from the state object.
Socket client = (Socket) ar.AsyncState;
try {
// Complete the connection.
client.EndConnect(ar);
var s = new byte[] { 1 };
client.Send(s);
var buf = new byte[1024];
var cnt = client.Receive(buf);
_logger.LogInformation($"## Connection to server successful at {client.RemoteEndPoint}");
if (cnt > 0) {
var returned = Encoding.UTF8.GetString(buf, 0, cnt);
_logger.LogInformation($"## Data returned: {returned}");
}
else {
_logger.LogInformation($"## No data returned");
}
finish.Set(); // signal end of program
}
catch (SocketException sockExcep) {
_logger.LogInformation($"## Exception: {sockExcep.Message}");
_logger.LogInformation("## Connection to server failed. Retrying...");
// This is a bad idea. You don't know what is wrong so retrying might not be useful.
// What if this is an unknown host or some other error that isn't likely to be
// resolved by a retry ???
RetryCount++;
if (RetryCount > 10) {
_logger.LogInformation("## Not able to reach host after 10 tries");
finish.Set(); // signal end of program
return; // give up
}
Thread.Sleep(797); // wait a bit
var dest = new DnsEndPoint(Hostname, Port);
client.BeginConnect(dest, new AsyncCallback(ConnectCallback), client);
}
catch (Exception ex) {
_logger.LogInformation($"## Exception: {ex.Message}");
}
_logger.LogInformation($"## ConnectCallback exited");
}
static void Main(string[] args) {
_logger = loggerFactory.CreateLogger<Program>();
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Blocking = true;
var dest = new DnsEndPoint(Hostname, Port);
_logger.LogInformation($"Attempting connection to {dest.Host}:{dest.Port}");
_logger.LogInformation($"Socket blocking: {client.Blocking}");
_logger.LogInformation("Calling BeginConnect");
var thd = client.BeginConnect(dest, new AsyncCallback(ConnectCallback), client);
_logger.LogInformation("BeginConnect complete");
_logger.LogInformation("Calling WaitOne");
finish.WaitOne(); // don't let program end until connection is made
_logger.LogInformation("WaitOne complete");
client.Close();
Thread.Sleep(25); // if you don't do this the program ends before all the log output can be written
Console.WriteLine("Program complete");
}
}
}
I've tested this code using .NET Core 2.1 and you'll need the following nuget packages to run it:
Microsoft.Extensions.Logging
Microsoft.Extensions.Logging.Console
Microsoft.Extensions.Logging.Debug"
Successful execution looks like this:
info: socketTst.Program[0]
Attempting connection to www.google.com:80
info: socketTst.Program[0]
Socket blocking: True
info: socketTst.Program[0]
Calling BeginConnect
info: socketTst.Program[0]
BeginConnect complete
info: socketTst.Program[0]
Calling WaitOne
info: socketTst.Program[0]
## ConnectCallback entered
info: socketTst.Program[0]
## Connection to server successful at 172.217.15.68:80
info: socketTst.Program[0]
## Data returned: HTTP/1.0 400 Bad Request
Content-Length: 54
Content-Type: text/html; charset=UTF-8
Date: Wed, 26 Sep 2018 03:32:39 GMT
<html><title>Error 400 (Bad Request)!!1</title></html>
Program complete
Related
This sample app creates a client-server connection via a TLS secured socket and sends some data over it:
static void Main(string[] args)
{
try
{
var listenerThread = new Thread(ListenerThreadEntry);
listenerThread.Start();
Thread.Sleep(TimeSpan.FromSeconds(1));
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
socket.Connect("localhost", Port);
var rawStream = new NetworkStream(socket);
using (var sslStream = new SslStream(rawStream, false, VerifyServerCertificate))
{
var certificate = new X509Certificate(CertsPath + #"test.cer");
var certificates = new X509CertificateCollection(new[] { certificate });
sslStream.AuthenticateAsClient("localhost", certificates, SslProtocols.Tls, false);
using (var writer = new StreamWriter(sslStream))
{
writer.WriteLine("TEST");
writer.Flush();
Thread.Sleep(TimeSpan.FromSeconds(10));
}
}
socket.Shutdown(SocketShutdown.Both);
socket.Disconnect(false);
Console.WriteLine("Success! Well, not really.");
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
}
private static bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
static void ListenerThreadEntry()
{
try
{
var listener = new TcpListener(IPAddress.Any, Port);
listener.Start();
var client = listener.AcceptTcpClient();
var serverCertificate = new X509Certificate2(CertsPath + #"\test.pfx");
var sslStream = new SslStream(client.GetStream(), false);
sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, false);
client.Close(); // terminate the connection
using (var reader = new StreamReader(sslStream))
{
var line = reader.ReadLine();
Console.WriteLine("> " + line);
}
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
}
The trick is that the connection is terminated from the server side immediately after handshake. And the problem is that the client side knows nothing about it; I'd expect the client side to raise an exception when it tries to send data over the closed connection, but it doesn't.
So, the question is: how do I detect such cases, when the connection was interrupted and data didn't really reach the server?
It is not possible to know which packets have arrived under the TCP model. TCP is a stream-oriented protocol, not a packet-oriented protocol; that is, it behaves like a bi-directional pipe. If you write 7 bytes, and then write 5 bytes, it's possible the other end will just get 12 bytes all at once. Worse, TCP's reliable delivery only guarantees that if the data arrives, it will do so in the correct order without duplication or rearrangement, and that if the data does not arrive, it will be resent.
If the connection is broken unexpectedly, TCP does not guarantee that you will know exactly what data was lost, nor is it reasonably possible to provide that information. The only thing the client knows is "I never received an acknowledgement for byte number N [and presumably not for the previous n bytes either], despite resending them multiple times." That is not enough information to determine whether byte N (and the other missing bytes) arrived at the server. It's possible that they did arrive and then the connection dropped, before the server could acknowledge them. It is also possible that they did not arrive at all. TCP cannot provide you with this information, because only the server knows it, and you are not connected to the server any longer.
Now, if you close the socket properly, using shutdown(2) or the .NET equivalent, then data in flight will be pushed through if possible, and the other end will error out promptly. Generally, we try to ensure that both sides agree on when to shutdown the connection. In HTTP, this is done with the Connection: Close header, in FTP with the BYE command, and so on. If one side shuts down unexpectedly, it may still cause data to be lost, because shutdown does not normally wait for acknowledgements.
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.
I apologize if this has been answered on SO. I looked but didn't find it. My situation is my customer can connect to their TCP server either by being on the local network, or coming in remotely via a Verizon modem. (I am using .NET 3.5 - C#)
When I connect from either of those, things are fine. But what if I am accidentally on the "wrong" network (ex: I am at Starbucks and logged onto their wireless network. I forget, thinking I am on the Verizon card, so, now I try to log in) The server refuses the connection. Fine. But my Try/Catch is not catching anything... it simply exits the routine (if I am calling it through threadpool) or it hangs if I call it directly.
Here is the code (it fails on: m_clientSocket.Connect(ipEnd) ):
tcpConnectionObject passedTCPObject = (tcpConnectionObject) obj;
if (checkNetStat(passedTCPObject) == false)
{
updateStatus(false);
return;
}
try
{
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(passedTCPObject.ipString);
int iPortNo = System.Convert.ToInt16(passedTCPObject.portString);
IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);
m_clientSocket.Connect(ipEnd);
if (m_clientSocket.Connected)
{
updateStatus(true);
//Wait for data asynchronously
WaitForData();
}
}
catch (SocketException e)
{
updateStatus(false);
return;
}
catch (Exception e)
{
updateStatus(false);
return;
}
updateStatus(true);
return ;
I call this from a Winform using the threadpool:
tcpConnectionObject passObject = new tcpConnectionObject(serverIP, serverPORT);
ThreadPool.QueueUserWorkItem(new WaitCallback(SRVR_CONNECT.connectToTCP), passObject);
This is called in the form's SHOW() method. When I do it like this, my form shows, but the status is never changed (which it should be by any result) If I put a debugger on it, and start stepping through the execution, I get to the Socket.Connect() and the debugger simply exits the mthod, and my form shows. I never hit any of my catches.
I have tried every error that Socket can generate, but it never catches anything. When I run my debugger, as soon as I hit that line, it exits my method, but there is no error that is catch-able.
If you really are waiting asynchronously (as you state in your comment), then you may be exiting the try/catch block before you actually get the exception.
It exits your method because you have a return statement inside of your catch block. You are telling it to return explicitly.
OK, I think Peter was on the right track. it seems like the debugger was simply skipping over my Connect line and moving on to the next line while waiting for the Socket.Connect() to finish (if that makes sense?)
Here's a change in the code that works... I move the packet creation, and the callback definition out of "WaitForData" and use the beginConnect method instead. Then I can set a timeout, which lets me know it fails -- so the code is changed to this:
try
{
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Cet the remote IP address
IPAddress ip = IPAddress.Parse(passedTCPObject.ipString);
int iPortNo = System.Convert.ToInt16(passedTCPObject.portString);
// Create the end point
ipEnd = new IPEndPoint(ip, iPortNo);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketPacket theSocPkt = new SocketPacket();
if (m_pfnCallBack == null)
{
m_pfnCallBack = new AsyncCallback(OnDataReceived);
}
// Give It 5 Seconds to connect
IAsyncResult result = socket.BeginConnect(ipEnd, m_pfnCallBack, theSocPkt);
bool success = result.AsyncWaitHandle.WaitOne(5000, true);
if (!success)
{
socket.Close();
throw new ApplicationException("Server Refused Connection");
}
// Success
updateStatus(true);
}
catch (SocketException e)
{
updateStatus(false);
return;
}
catch (Exception e)
{
updateStatus(false);
return;
}
I wrote a TCP server to use the BeginAccept/EndAccept pattern. With this, I coded up a simple UnitTest using a TcpClient, and measured each portion. All tests are localhost, so I am surprised to see that TCP connection is consistently taking 1 second. I have set the Socket.NoDelay = true although I believe this only affects Send/Receive. I am not receiving the first packet of data. Any help or ideas on speed this up are appreciated.
Note: I can not change the client side to keep the connection open, and I need to be able to handle a lot of requests per second if possible.
Server Side:
public void Start()
{
System.Net.IPHostEntry localhost = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
System.Net.IPEndPoint endpoint;
int port = Properties.Settings.Default.ListenPort;
//
// Setup the connection to listen on the first IP, and specified port
//
endpoint = new IPEndPoint(IPAddress.Any, port);
listenSocket = new Socket(endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(endpoint);
listenSocket.NoDelay = true; // do not wait 200 milliseconds for new data to be buffered on the connection
listenSocket.Listen(int.MaxValue);
Console.WriteLine("Listening on {0}:{1}", localhost.AddressList[0], port);
//
// Post the accept. The accept method will continuously post a new accept as soon as a connection is made
//
while (true)
{
accepted.Reset();
Connection connection = connections.Pop();
listenSocket.BeginAccept(AcceptCallback, connection);
accepted.WaitOne();
}
}
private static void AcceptCallback(IAsyncResult ar)
{
accepted.Set();
Connection connection = ar.AsyncState as Connection;
Socket remoteSocket = null;
try
{
remoteSocket = listenSocket.EndAccept(ar);
remoteSocket.NoDelay = true;
connection.RemoteSocket = remoteSocket;
//
// Start the Receive cycle
//
Receive(connection);
}
catch (SocketException)
{
Disconnect(connection);
}
}
Simple Test Client:
[TestMethod()]
public void ClientTest()
{
TestContext.BeginTimer("Connection");
TcpClient client = new TcpClient("localhost", 10300);
NetworkStream stream = client.GetStream();
TestContext.EndTimer("Connection");
...
Using a LoadTest I loaded 25 users, and the Transaction "Connection" always takes above 1 second.
Not sure why, but simply changing this:
TestContext.BeginTimer("Connection");
TcpClient client = new TcpClient("localhost", 10300);
TestContext.EndTimer("Connection");
To this:
TestContext.BeginTimer("Connection");
TcpClient client = new TcpClient();
client.Connect("localhost", 10300);
TestContext.EndTimer("Connection");
Drops the time from 1 second to .13 seconds. Will have to investigate as to why, but hopefully this will help somebody out in the future.
When you attempt to connect using the TcpClient constructor on a host that resolves to both Ipv6 and Ipv4 addresses, the connection using Ipv6 is attempted first. If it fails then it attempts to connect using the Ipv6 address. This is the cause of the 1 second delay. Here is the MSDN link:
I'm using the code below, it seem sometime the socket is not released
How did I found that?
by using process explorer(from sysinternal),
proprieties on the application
then going into TCP/IP tab.
I can see the port being used by typing "netstat -a" into a console
My problem is, after a while (like 5 weeks) there is like 40 port used by the application while it should be zero.
Anyone know why it does that?
public void Connect()
{
try {
// Resolve server address
IPHostEntry hostadd = Dns.GetHostEntry(TimeServer);
IPEndPoint EPhost = new IPEndPoint(hostadd.AddressList[0], 123);
//Connect the time server
UdpClient TimeSocket = new UdpClient();
TimeSocket.Connect(EPhost);
TimeSocket.Send(SNTPData, SNTPData.Length);
SNTPData = TimeSocket.Receive(ref EPhost);
TimeSocket.Close();
if (!IsResponseValid())
{
throw new Exception("Invalid response from " + TimeServer);
}
} catch(SocketException e)
{
throw new Exception(e.Message);
}
}
You're blocking forever on:
SNTPData = TimeSocket.Receive(ref EPhost);
If the socket never receives a packet it will sit there waiting until the process dies.
You'll need to close the socket by calling TimeSocket.Close() on a different thread or by setting a timeout on the receive using SetSocketOption.