I notice via netstat that the RO connections are kept alive when I do not want this
I have a set of HTTPS RO cloud servers that communicate with eachother.
My code is using a using() statement and disposes channel and message.
However the TCP connection remains established after the dispose.
The channel KeepAlive property is true
For the connections to other servers one TCP connection is created and reused.
For the connection to itself (via URL) the connection gets created multiple times.
After a period of time the TCP connection goes to TIME_WAIT and gets removed but multiple connections to oneself exist
What could be the reason? How do I explicitely dispose all resources?
Example of netstat connections a connection to oneself is shown on two lines (once client and once server perspective)
TCP 192.168.168.27:7572 192.168.167.10:50657 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:41160 TIME_WAIT
TCP 192.168.168.27:7572 192.168.168.1:41250 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:41254 ESTABLISHED
TCP 192.168.168.27:41250 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:41254 81.82.213.199:7572 ESTABLISHED
TCP [::]:7572 [::]:0 LISTENING
In our code we create 1 channel and 1 message (which we dispose) but then create multiple service interfaces (which we don’t dispose).
Is the service disposable? Should it be disposed?
This is our code
using (var cloudServerClient = new OffCloudServerClient.CloudServerClient(endpoint.url, userid, clientname, cloudpwd, tags,conconfig))
{
if (cloudServerClient.connect(out errormsg))
{
cloudServerClient.itfManagement().getCloudServerUniqueID();
...
cloudServerClient.itfManagement().getCloudData(...);
}
} // end using
The OffCloudServerClient class is our own helper class which supports IDisposable and has following relevant functions
bool connect(...)
{
// creates another of our own custom helper classes which is put in member field roCon which contains code
this.clientChannel = RemObjects.SDK.ClientChannel.ChannelMatchingTargetUri(uri);
this.message = new RemObjects.SDK.BinMessage();
// perform login
bLoginOK = this.performLogin(false);
// which contains
var itfLogin = OffCloudServer.CoCloudPharmacyLoginService.Create(roCon.message, roCon.clientChannel);
...
bool bRet=itfLogin.Login(curSessionUser, jsonLoginData);
}
public void Dispose()
{
if (this.message != null)
this.message.Dispose();
if (this.clientChannel is IDisposable)
((IDisposable)this.clientChannel).Dispose();
}
public OffCloudServer.IManagementService itfManagement()
{
return OffCloudServer.CoManagementService.Create(roCon.message, roCon.clientChannel);
}
using (var cloudServerClient = new OffCloudServerClient.CloudServerClient(endpoint.url, userid, clientname, cloudpwd, tags,conconfig))
{
if (cloudServerClient.connect(out errormsg))
{
var svc = cloudServerClient.itfManagement(); // reuse existing service
svc.getCloudServerUniqueID();
...
svc.getCloudData(...);
}
} // end using
OK, I will modify my code in a similar way.
FYI: I believe putting the keepalive parameter of the IpHttpClientChannel object to False already improved the situation
I still have some questions
What about the login services? CoCloudPharmacyLoginService.Create. Each service call is preceded by such a service creation and call to Login.
Should a RO service be disposed to free the TCP connection ASAP?
In general: how can we release the TCP connection cleanly. I am afraid what happens now is not a perfect TCP finalization handshake. netstat shows FIN_WAIT_2 and TIME_WAIT for a few seconds.
I could be mistaken but I believe a correct TCP finalization handshake instantly closes the connection.
You can put login method to OnLoginNeeded event so it will be login when server requires it (i.e. when SessionNotFoundException is raised on server-side).
note: you are using HTTPS connections, so it has own logic. I’ve seen something similar on Delphi platform with SSL connections.
Can you reproduce the same case with plain http (not https) connections?
Yes, I have put the login method in the ClientChannel_OnLoginNeeded event. I am just pointing out that that function creates a login service each time.
Is that problematic?
Can you tell me how a connection can be closed immediately?
The disposing of the channel does not appear to do the trick.
For a set of sequential calls create/connect/RO call/dispose a bunch of connections remain
It is not a big issue since they get cleaned up after 2 to 5 minutes but it makes analysing the network and port usage harder.
TCP 192.168.168.27:59903 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60317 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60334 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60335 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60336 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60337 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60338 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60345 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60346 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60347 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60348 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60350 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60351 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60355 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:60356 81.82.213.199:7572 ESTABLISHED
I modified some code so it also supports plain HTTP.
The behaviour looks similar.
Note: Some simultaneous requests are performed so it is hard to evaluate how many connections are waranted but the dispose definately does not close the connection immediately
λ netstat -a -n | grep 7572
STDIN
TCP 0.0.0.0:7572 0.0.0.0:0 LISTENING
TCP 192.168.168.27:7572 78.21.37.126:54717 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55669 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55670 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55671 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55672 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55673 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55674 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55676 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55687 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55688 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55690 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55691 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55692 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55695 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55697 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55701 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55702 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55703 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55704 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55705 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55706 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55708 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55714 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55715 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55716 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55717 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55718 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55720 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55724 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55725 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55726 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55727 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55728 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55729 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55731 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55734 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55735 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55736 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55738 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55739 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55740 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55741 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55744 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55745 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55746 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55747 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55748 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55750 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55754 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55755 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55756 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55757 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55758 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55759 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55762 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55765 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55766 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55767 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55769 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55770 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55771 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55772 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55773 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55774 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55775 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55776 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55777 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55778 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55779 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55780 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55782 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55783 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55795 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55796 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55798 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55799 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55801 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55802 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55803 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55804 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55806 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55807 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55808 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55809 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55811 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55812 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55813 ESTABLISHED
TCP 192.168.168.27:7572 78.21.37.126:55814 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:62806 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:62825 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63008 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63009 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63010 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63011 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63032 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63033 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63034 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63035 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63039 ESTABLISHED
TCP 192.168.168.27:7572 192.168.168.1:63040 ESTABLISHED
TCP 192.168.168.27:62806 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:62825 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63008 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63009 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63010 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63011 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63032 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63033 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63034 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63035 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63039 81.82.213.199:7572 ESTABLISHED
TCP 192.168.168.27:63040 81.82.213.199:7572 ESTABLISHED
TCP [::]:7572 [::]:0 LISTENING
It will close the .NET part of the socket. However according to the TCP specification the OS have to keep the lower level tidbits of the socket open for a certain amount of time in order to detect retransmission, and similar. In this particular case it’s likely keeping the socket around for a bit in order to detect a reply to the SYN packet sent so it can reply more sensibly and not mix up the reply with further packets sent.