Async TcpClient Connect different when deployed on Windows and Linux - c#

I'm writing a client application, that has to connect to a server application via TCP socket. The framework of choice is .NET Core 2.0 (it is not ASP.NET Core it is just a console app). I'm using a TcpClient class, and its .BeginConnect() and .EndConnect() methods, to be able to set a connection timeout. Here is the code:
public class Program
{
public static void Main(String[] args)
{
var c = new TcpClient();
int retryCount = 0;
var success = false;
IAsyncResult res;
do
{
if (retryCount > 0) Console.WriteLine("Retry: {0}", retryCount);
retryCount++;
c.Close();
c = new TcpClient();
res = c.BeginConnect("10.64.4.49", 13000, null, null);
success = res.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2));
Console.WriteLine(success.ToString());
}
while (!c.Connected);
c.EndConnect(res);
Console.WriteLine("Connected");
Console.ReadLine();
}
When I compile, publish and run this Console App, and nothing is listening on the IP address and port, the results if the app is running on Windows or Linux are different.
Here are the results on Windows:
Here is what it looks like on Linux:
The results are pretty the same, the only difference is on Windows it tries to connect every two seconds, but on Linux, it acts like this two seconds are ignored and goes on a "rampage connection session" as I call it.
I'm not sure if this is a .NET Core issue or some Linux tune-up, that Windows already have predefined.
Can anyone advice what might be the problem, and eventually propose a solution.
Thanks in advance,
Julian Dimitrov

I think I understand why you're having an issue, and it seems to be based upon a misunderstanding of what a timeout should do.
For the sake of testing, I changed your code to this:
var sw = Stopwatch.StartNew();
res = c.BeginConnect("127.0.0.1", 12, null, null);
success = res.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(10));
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
On Windows, I can see that the connection fails after ~1 second, whereas running the same code within Linux, it fails almost instantly. It seems that Linux is capable of working out if a connection is possible faster than Windows is. I think perhaps you're mistaking the time Windows takes to work out it can't connect with the timeout you've specified.
Next: What is a timeout? A timeout is the maximum time a connection can take to be established. It's a limit. It means that the operation has to complete in less than X seconds (e.g. 10 seconds) or it fails. If an operation completes in 1 second, then it will be immediately returned.

Related

Connecting to local EventStore is not being maintained when debugging .NET application

Problem: my connection to a locally stored EventStore is not being maintained when I debug my .NET application from Visual Studio.
I get an error:
Connection 'ES-6ab8f860-e44b-40ca-93fa-7370b72547d8' was closed.
Current setup: my Event Store is placed in my solution, application referenced by a PATH variable.
//Path to the local EventStore in solution
private const string Path = #"..\..\EventStore-OSS-Win-v5.0.8\EventStore.ClusterNode.exe";
The following code setups a new connection to the EventStore:
public static void SetupEventStore(StartConflictOption opt = StartConflictOption.Connect) //set default to Connect
{
// Save the EventStore process in a variable for later use
var runningEventStores = Process.GetProcessesByName("EventStore.ClusterNode");
// if a process was found, check the parameter options on what to do with the process
if (runningEventStores.Length != 0)
{
switch (opt)
{
case StartConflictOption.Connect:
_process = runningEventStores[0]; //set the process to the EventStore.ClusterNode
break;
case StartConflictOption.Kill:
foreach (var es in runningEventStores) //makes sure that all running processes are killed
{
es.Kill();
}
break;
case StartConflictOption.Error:
throw new Exception("Conflicting EventStore running."); //Will be thrown if there is already a running EventStore process
default:
throw new ArgumentOutOfRangeException(nameof(opt), opt, null);
}
}
if (_process == null)
{
_process = new Process
{
StartInfo =
{
UseShellExecute = false, CreateNoWindow = true, FileName = Path, Arguments = Args, Verb = "runas"
}
};
_process.Start();
}
//set default IP endpoint and port (localhost:1113). HTTP uses port 2113, while TCP uses port 1113
var tcp = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1113);
var http = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2113);
//Connect to the Event Store
Connection = EventStoreConnection.Create(new Uri("tcp://admin:changeit#localhost:1113"));
Connection.ConnectAsync().Wait();
}
When I debug the application, it starts up without issues, but when I attempt to create a new stream to the EventStore, it crashes with the previously mentioned error.
I noticed that the EventStore process is active for a split second, before being terminated when debugging the application.
Question: why is my Event Store process not being maintained while the application is running and what steps can I take to fix this issue?
The answer to your question is below, but first, let me express my worry about your setup. I could never imagine an application to execute a database that it uses in a similar fashion. What is the reason to start Event Store from your application, why can't it be started in a different way? Using process.Kill on any database, not only Event Store, is also not the best idea.
If you must carry Event Store as a part of your application, I'd suggest using the embedded version instead (not guaranteed that it will survive in future versions though).
What you observe is normal behaviour. The same happens with any real-time always-on connection, like gRPC streaming.
When you are step-debugging your app and stand still at the breakpoint, the world stops for the whole application. There's no multi-threading or anything else that works when you hit the breakpoint and don't move on.
In practice, you should prepare your application to handle connection failures. One of the fallacies of distributed computing is that "the network is reliable". It is not. The IEventStoreConnection instance has a few events, like
_connection.Disconnected += (sender, args) =>
{
log.Warning("Connection closed");
Task.Run(() => Reconnect()); // Reconnect is some place when you try to connect again
};
I would advise avoiding step-in debugging overall and in applications that use always-on communications in particular. You can get much more value from writing tests that cover your use cases and. Logs are useful too.
If you absolutely must debug with breakpoints, you can change your local environment settings so the connection string will be more tolerant of being disconnected. Check the list of settings in the docs. Some settings that might help are HeartbeatInterval and HeartbeatTimeout. By setting those settings to a minute (for example), you will have enough time for debugging before the connection closes. Do not use such values in production though.
You can also instruct the connection to keep reconnecting (KeepReconnecting(). You need to use the ConnectionSettingsBuilder parameter in the code that creates the connection. There are methods to adjust the heartbeat interval and timeout there as well, which you can use instead of changing the connection string. Using different connection strings though is easier since you can have different configuration files per environment in .NET Core.
An example:
var connectionString = $"ConnectTo=tcp://{user}:{password}#{host}:1113; HeartBeatTimeout=500";
var settingsBuilder = ConnectionSettings
.Create()
.KeepReconnecting()
.LimitReconnectionsTo(10);
_connection = EventStoreConnection.Create(connectionString, settingsBuilder);

.NET remoting target refusing a single call - returns socketexception

I have an old school .NET remoting app that I needed to extend a little. As part of that, I brought it to .NET 4.0. (was .NET 2.0 before) The interface that is hosted looks like this
public interface IRemoteSupportVM
{
string runAnOperation(Customer cust, List<CustomRoute> routes);
string runAnotherOperation(string customer, string routes);
string runAThirdOperation(List<string> pathsToBeCleaned);
string writeFile(string path, string filename, int type, byte[] data);
string readFile(string path, string filename, out byte[] data);
string deleteFile(string path, string filename);
long ping();
}
ping, readFile, writeFile and deleteFile work just fine. When I call runAnOperation/runAnotherOperation/runAThirdOperation, I get an immediate SocketExcepting telling me
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
Now I now that's a bunch of baloney because all the other calls work just fine, and, the target does get the call and performs its thing. But since the client thinks the call failed, everything that comes after calling connect fails too.
the solution has a bunch of other remoting interfaces, and as far as I can tell, they all work except these two method calls. Any idea what could trip up the .NET remoting caller?
#edit: I noted another thing: the run* operations take a while to complete. The other operations return immediately. As I have the code of both sides of the remoting interface, I set a breakpoint on the implementation of ping(), and now I also get a SocketException when the client calls ping. So it seems to be a timeout I'm not aware of.
Okay, so after a painful trial & error period, I finally found the culprit. It's the timeout of the channel when it gets initialized. That's how it was in the remote side code:
IDictionary props = new Hashtable
{
["port"] = config.Port,
["timeout"] = config.RemotingTimeout,
};
var channel = new TcpChannel(props, clientProv, serverProv);
Now it appears that the timeout property had no effect on .NET 2.0 - there's quite a few google results towards that effect. However, in .NET 4.0 it suddenly seems to take. Every remoting call is wrapped IAsync* Begin/EnvInvoke to ensure a result after the desired timeout (even if that result is that the server didn't provide a result in time). So either nobody every noticed that timeout had no meaning or the execution wrapper was put in place for exactly that reason (the software was started 15 years ago.. so who knows).
As config.RemotingTimeout was 70, a call had 70 miliseconds to complete or I'd get the SocketException. When I converted the 70 seconds (that I was expecting) to milliseconds ( so timeout = 70000), things suddenly started working the way I expected them to.

Windows service - unrecoverable FtpWebRequest timeout when an FTP provider maintenance window occurs

I have a windows service, where every hour on a scheduled basis it downloads an FTP file from an FTP server. It uses the following code to do this:
var _request = (FtpWebRequest)WebRequest.Create(configuration.Url);
_request.Method = WebRequestMethods.Ftp.DownloadFile;
_request.Timeout = 20000;
_request.Credentials = new NetworkCredential("auser", "apassword");
using (var _response = (FtpWebResponse)_request.GetResponse())
using (var _responseStream = _response.GetResponseStream())
using (var _streamReader = new StreamReader(_responseStream))
{
this.c_fileData = _streamReader.ReadToEnd();
}
Normally, the downloading the FTP data works perfectly fine, however every few months the FTP server provider notifies us that some maintenance needs to be performed. So once maintenance is started (usually only 2 or 3 hours), our hourly attempt of a FTP download fails - i.e. it timeout, which is expected.
The problem is that post the maintenance window our windows service continues to timeout every time it attempts to download the file. Our windows service also has retry logic, but each retry also times out.
Once we do a restart of the windows service, the application starts downloading FTP files successfully again.
Does anyone know why we have to restart the windows service in order to recover from this failure?, Could it be a network issue e.g. DNS?
Note 1: There are similar questions to this one already, but they do not involve a maintenance window and they also do not have any credible answers either
Note 2: We profiled the memory of the application and it seems all ftp objects are being disposed of correctly.
Note 3: We executed a console app with same FTP code post maintenance window and it works fine, while the windows service was still timing out
Any help much appreciated
We eventually got to the bottom of this issue albeit not all questions were answered.
We found that when we used a different memory profiler, it showed up that two FtpWebRequest objects were in memory and had not been disposed for days in the process. These objects were what was causing the problem i.e. they were not being properly disposed.
From research, to solve the issue, we did the following:
Set the keep-alive to false
Set the connections lease timeout to a limited timeout value
Set the max idle time to a limited timeout value
Wrapped in a try/catch/finally, where the request is aborted in the finally block
We changed the code to the following:
var _request = (FtpWebRequest)WebRequest.Create(configuration.Url);
_request.Method = WebRequestMethods.Ftp.DownloadFile;
_request.Timeout = 20000;
_request.Credentials = new NetworkCredential("auser", "apassword");
_request.KeepAlive = false;
_request.ServicePoint.ConnectionLeaseTimeout = 20000;
_request.ServicePoint.MaxIdleTime = 20000;
try
{
using (var _response = (FtpWebResponse)_request.GetResponse())
using (var _responseStream = _response.GetResponseStream())
using (var _streamReader = new StreamReader(_responseStream))
{
this.c_fileData = _streamReader.ReadToEnd();
}
}
catch (Exception genericException)
{
throw genericException;
}
finally
{
_request.Abort();
}
To be honest we are not sure if we needed to do everything here but the problem no longer exists i.e. objects do not hang around, the application still functions post a maintenance window so we are happy!

TCPClient & Sockets failing to connect to the Server

I have a very strange problem with my connection to a server on a TCPListener/TCPClient basis. At some point during testing I am unable to connect to my server-application anymore, every try it times out. Netstats on both sides show, that my application listens on the right port, and the client is trying to connect to the right ip and port, but it does not advance further than "SYN_SENT". The server just displays "LISTENING" all the time. All I can do is restart my PC, which temporarily fixes this problem. But after some connections, it starts all over again.
Up to now I tested TCPClient and Sockets class to connect to the server but both show this behaviour, what is not surprising, as TCPClient is a wrapper around the Sockets Class afaik.
Firewall is checked on both sides, things like Remote Desktop work perfectly fine, and is not blocking the Connection of my Application. There are no connections left to close or something, already cheked everything I know (maybe not that much ;) )
So whats the problem?
Edit:
A Method that needs to connect to my Server:
public int GetSomeDataFromServer(string blargh)
{
int ret;
try
{
using(ConnectionTCPStream ctp = new ConnectionTCPStream())
{
if(ctp.EstSecConnWithServ())
{
ret = CKSHandler(ctp, blargh);
}
else
{ ret = (int)ErrFlags.ServerDeniedConnection; }
}
return ret;
}
catch(Exception)
{
InternalError = ErrFlags.ServerUnreachable;
return (int)ErrFlags.ServerUnreachable;
}
}
The Constructor of my Class that is dealing with the Connections:
public ConnectionTCPStream()
{
Client = new TcpClient("VeryImportantAdress", 49778); //it fails right here!
rsaCrypt = new RSACH() { RSAForeignPubKey = "An 8192-Bit long RSA Public key." };
AESPASS = AESThenHMAC.CreatePassword(200);
}
Sounds like you are using up all your connections or some other resource.
What do you see when you do a netstat -an ? Do you see a bunch of open ports?
There an Article Here that could possibly help you here
Some other resource may be killing you, might be worth having an SA fire up a resource monitor to check the health of the host when you run into this situation.
If there's no errors being thrown, it makes your life that much harder. The problem typically happens when you don't cleanly clean up your socket disconnects.
The answer is the firewall which changed its mind every now and then. I couldn't test that before because i had no access to it. Now i have changed settings while i had this blockade and it worked fine again. So the answer is: Always have access to the firewall and don't forget to check it.

call controller by timer

I have to send query to remote program and recieve data. Then put them in my DB.
This is possible to call controller's action every 60 seconds for example?
Thanks.
PS. I think it's must be done on server side. Not JS solution.
UPDATE:
First, I have MS SQL Server DB.
Second, There is remote program that listen specific TCP port and waiting a query. I want to send a query every 60 seconds and parse response, then put parsed data in my MS SQL Server DB.
Using Ajax you could create a timer to send data to the controller every x seconds .
A spellchecker plugin in my web application does this , to do spell checking as you type .
I think you would be better off using a standalone service (windows, wcf, msmq, etc) that runs in the background and "sends the query" and saves to your DB.
Web Applications are not designed to be utilized as time-based "always alive" mechanisms. "Timing" needs state, and HTTP is a stateless protocol.
Don't try to shoehorn functionality into something that isn't designed to handle it.
Then again i could be completely misunderstanding your question. Quite possible.
Confusing statements:
This is possible to call controller's action
If it's external, how do you know it's a controller? Is this an external API?
There is remote program that listen specific TCP port and waiting a query
That doesn't sound like a web application/controller.
You could use cron on *nix base system. Or your program could trigger events every hours
0 * * * * lynx url-of-your-program-address.com/action/to/call
Your question is confusing. But since we are only here to guess at what you are on about here's a solution that might come close.
(P.S. I haven't compiled or tested this...because why should I care)
class ConsoleApplication
{
public static void Main()
{
Timer myTimer = new Timer();
myTimer.Elapsed += new ElapsedEventHandler( DoAction );
myTimer.Interval = 1000;
myTimer.Start();
while ( Console.Read() != 'q' )
{
; // do nothing...
}
}
public static void DoAction( object source, ElapsedEventArgs e )
{
Console.WriteLine("Made request at {0}", DateTime.Now);
using (WebClient client = new WebClient())
{
using (Stream stream = client.OpenRead("http://whereever"))
using (StreamReader reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
}
}
Depending on how flexible your solution should be I would play around with Windows Service solution with Timer in it either with Quartz.Net.
You can find more details using the link below http://quartznet.sourceforge.net/

Categories