I continue working on my TCP sockets, as mentioned this morning.
I have discovered that the amount of sockets keeps growing, every time I send a message over such a socket. This simply means that I am constantly creating and opening new sockets instead of re-using the already opened ones.
In my application, I have a repository of connections, and I only need to use one of them. But I'm afraid that I'm constantly creating new ones. This is the way it is done:
public static class Repository
{
...
public static Conn GetByName(string name, ...)
{
return result =
context.Set<Conn>().Where(o => o.Name == name).FirstOrDefault();
}
}
...
Conn Connection_For_Message = Repository.GetByName(request.ConnectionName, ...);
According to me:
Repository
is declared static
causes one single object to be created internally.GetByName()
method performs a FirstOrDefault()
of a Where()
method, this is giving the already existing object, and it does not create a new one.Now I have the impression that 1. is correct, but 2. is wrong, in the sense that Connection Connection_For_Message
always creates a new instance of an object.
Is my impression correct and if yes, how can I solve this? I was thinking of altering Repository
from a static class into a singleton, but I don't find an ISingleton
or something in System.Reflection
, or am I looking the completely wrong direction?
Edit: Hereby a part of the constructor of the Conn
class:
public Conn(...)
{
...
TcpConnection = new TcpConnection(...); // in here a
...
}
As far as the TcpConnection
class is concerned:
public class TcpConnection : IDisposable
{
public Socket _socket;
...
Every time I send a message, I pass by the GetByName()
method and my call stack looks as follows:
My_Application.dll!TcpConnection.TcpConnection(...) Line 39 C#
> My_Application.dll!Conn.Conn(...) Line 32 C#
[External Code]
My_Application.dll!ConnectionRepository.GetByName(string name, ...) Line 71 C#
The line, marked with >
is the constructor, which proves indeed that GetByName()
is calling the Conn
constructor indeed. (Oh, and why is there "External code" between the GetByName()
method and the constructor?)
Edit again: I have managed showing the external code, hereby the callstack with "Show External Code" checked:
> My_Application.dll!TcpConnection.TcpConnection(...) Line 39 C#
My_Application.dll!Conn.Conn(...) Line 32 C#
[Native to Managed Transition]
[Managed to Native Transition]
System.Private.CoreLib.dll!System.Reflection.RuntimeConstructorInfo.Invoke(System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, object[] parameters, System.Globalization.CultureInfo culture) C#
System.Private.CoreLib.dll!System.RuntimeType.CreateInstanceImpl(System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, object[] args, System.Globalization.CultureInfo culture) C#
System.Private.CoreLib.dll!System.Activator.CreateInstance(System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) C#
Castle.Core.dll!Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(System.Type proxyType, System.Collections.Generic.List<object> proxyArguments, System.Type classToProxy, object[] constructorArguments) C#
[Lightweight Function]
Microsoft.EntityFrameworkCore.Relational.dll!Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable<Conn>.Enumerator.MoveNext() C#
System.Linq.dll!System.Linq.Enumerable.TryGetSingle<Conn>(System.Collections.Generic.IEnumerable<Conn> source, out bool found) C#
[Lightweight Function]
System.Linq.Queryable.dll!System.Linq.Queryable.FirstOrDefault<Conn>(System.Linq.IQueryable<Conn> source) C#
My_Application.dll!ConnectionRepository.GetByName(string name, ...) Line 71 C#
You are querying database with Entity Framework to get Conn (as we can see from callstack). Database of course cannot store such thing as TCP connection. Every time you do the query, new instance of Conn is returned (technically it can be returned from cache but it doesn't change the situation), although it represents the same database row. Creating TCP Client in constructor of a class which represents database entry is not a good idea.
Instead you can use ConcurrentDictionary<string, TcpConnection>
to manage your connections in a thread-safe way.