Toemsel / Network

C# Network Library

Home Page:https://push-force.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How do I close the connection nicely?

Hulkstance opened this issue · comments

If I do the following in the Client:

tcpConnection.Close(Network.Enums.CloseReason.ClientClosed);

it closes the connection but the connection remains there, you can see that in Process Hacker in Network tab. Any solution for this?

Does the server receive the close event? Do you use the ClientConnectionContainer?

It does. It receives ClientClosed.

Ok, I will invest the issue. What software do you use to filter running child threads?

Process Hacker. It shows the remaining connection. And by the way, if you reconnect to the server, it closes the remaining connection and opens a new one. Probably something is wrong with Close method.

Code here:

// Server
_serverConnectionContainer = ConnectionFactory.CreateServerConnectionContainer(1234, false);

_serverConnectionContainer.ConnectionLost += (a, b, c) => Console.WriteLine($"{a.IPRemoteEndPoint} disconnected. Reason: {c}.");
_serverConnectionContainer.ConnectionEstablished += connectionEstablished;

_serverConnectionContainer.Start();

private static void connectionEstablished(Connection connection, ConnectionType type)
{
	Console.WriteLine($"{connection.IPRemoteEndPoint} connected. Online: {_serverConnectionContainer.Count}.");

	connection.RegisterRawDataHandler("file", (rawData, con) =>
	{
		Console.WriteLine("Received file size: {rawData.Data.Length}");

		connection.SendRawData("file_received", Encoding.UTF8.GetBytes("Hello from Server. File was received."));
	});

	connection.RegisterRawDataHandler("message", (rawData, con) => {
		Console.WriteLine("Received message: {rawData.ToUTF8String()}");
	});
}

// Client code
ConnectionResult connectionResult = ConnectionResult.TCPConnectionNotAlive;
TcpConnection tcpConnection = ConnectionFactory.CreateTcpConnection("127.0.0.1", 1234, out connectionResult);

if (connectionResult == ConnectionResult.Connected)
{
	tcpConnection.SendRawData("file", File.ReadAllBytes(path));
	tcpConnection.SendRawData("message", Encoding.UTF8.GetBytes("Hello, Server!"));

	tcpConnection.RegisterRawDataHandler("file_received", (rawData, con) =>
	{
		string serverMessage = rawData.ToUTF8String();

		tcpConnection.Close(Network.Enums.CloseReason.ClientClosed);
	});
}```

I debugged it and seems to be invokePacketThread.AbortSave(); throwing ThreadAbortException.

In InvokeWork(), you can see that it received the CloseRequest but it fails to abort the thread at HandleDefaultPackets(toDelegate); and later in ExternalClose(closeRequest.CloseReason);. It leads to AbortSave(). In other words, invokePacketThread cannot be aborted. Perhaps, because it was aborted somewhere earlier?

I added Thread.ResetAbort(); in AbortSave() to make it work which is not the best solution. You can check your code.

This is all I did:

    /// <summary>
    /// Provides additional functionality to the <see cref="Thread"/> class, that isn't available under .NET Standard 2.0.
    /// </summary>
    internal static class ThreadExtensions
    {
        #region Methods

        /// <summary>
        /// Allows for a <see cref="Thread"/> object to be aborted in a program running under the .NET Standard C# implementation.
        /// </summary>
        /// <param name="thread">The <see cref="Thread"/> instance this extension method affects.</param>
        /// <returns>Whether the <see cref="Thread.Abort(object)"/> method raised an exception.</returns>
        internal static bool AbortSave(this Thread thread)
        {
            try
            {
                thread.Abort();
                return false;
            }
            catch
            {
                Thread.ResetAbort();
                return true;
            }
        }

        #endregion Methods
    }

Thanks for the invest. While trying to resolve the issue, I encountered that .NET Core doesn't support Thread.Abort. Besides switching completely to a task related behaviour, I try to find a workaround.

No problem. This is a solution meanwhile.

I wasn't able to find any remaining threads after closing the connection.
On .NET 4.6 > and >.NET Core the AbortSave() does abort the network threads successfully.
Maybe you didn't set "AutoReconnect" to false, in order to prevent a reconnection?

Thread.ResetAbort() isn't a solution, since it aborts the abortion.

Please add some screenshots, highlighting the remaining threads. Or, even better, provide an example illustrating the issue.

This is a real issue. My app is not working. The connection remains and even tieouts and appears as a different message when debugging(because it timeouts further in time). Is there a fix for this?

.NET or .NET Core?

Can you provide a minimalistic example?

Related to #55