Sockets not cleaned up on Editor restart

Hello,

I have an editor plugin which sets up a listener socket for third party clients to communicate with (on the same machine). The plugin fails to clean up the connection and the sockets on shutdown. The problem specifically arises when I do a restart of the Editor (with the same project or a new one which has the same plugin enabled). There is no problem when I quit UE4Editor altogether and then restart manually


UDP

I have the following code in my StartupModule function for UDP:

ListenerSocket = FUdpSocketBuilder(TEXT("MySocket"))
		.BoundToEndpoint(DEFAULT_ENDPOINT)
		.Build();
mySocketReceiver = new FUdpSocketReceiver(Client, FTimespan(0, 1, 0), TEXT("MyUDPSocketReceiver"));
mySocketReceiver->OnDataReceived().BindRaw(this, &FMyPlugin::OnDataReceived);

ShutdownModule function for UDP:

if (ListenerSocket != NULL)
{
	ListenerSocket->Close();
	ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ListenerSocket);
	ListenerSocket = NULL;
}
mySocketReceiver->Stop();
delete mySocketReceiver;
mySocketReceiver = NULL;

I’ve even tried putting this at the end:

ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->Shutdown();

The plugin does call my shutdown function when the editor restarts but when the new editor launches and tries to re-bind (in the startup module function) to the same address/port, it fails to create a socket through FUdpSocketBuilder, failing on Socket.Bind.

On further investigation using Microsoft’s TCPView. I can see that the previous connection isn’t terminated and the address/port is bound to the previous editor instance’s connection.

(Note: I’ve also tried adding the AsReusable attribute to FUdpSocketBuilder).


TCP

I’ve seen similar behaviour in a TCP listener implementation. The code was as follows:

StartupModule for TCP

TcpListener = new FTcpListener(DEFAULT_ENDPOINT);
TcpListener->OnConnectionAccepted().BindRaw(this, &FMyPlugin::HandleConnectionAccepted);

ShutdownModule for TCP

if(Client != NULL)
{
	Client->Close();
	Client=NULL;
}
TcpListener->Stop();
delete TcpListener;
TcpListener = NULL;

In TCP’s case, the communication just fails silently (I assume the data is being sent to the previous editor process’s port). Our new editor instance doesn’t even receive the OnConnectionAccepted callback.

Hi Sameer,

I checked in a fix for dangling socket handles on Windows (GitHub Commit). With that change I no longer see sockets not being closed. Can you try whether it fixes your problem as well? Thanks!

Hi gmpreussner,

Yes this fix indeed resolves our issue as well. Thanks for the update. When can we expect this fix to be in a release build ?

This will not make it into the 4.6 branch as testing on it is pretty much complete now, and it will be released any day. You may have to wait for 4.7, but I will try to get this fix into a 4.6 hotfix.

Thanks for the help and the info on release!

Hi gmpreussner,

Did this get into the 4.6 hotfix? I don’t see anything related in the release notes though. Can we get an update on when this will be added to the release build?

Thanks!

This issue was not critical enough to make it into the hotfix. You will have to either compile yourself from the Master branch or wait for 4.7.

@gmpreussner

Im currently having the same issue in 4.7.2 even though it seems the above fix made it into 4.7. Im using the following in my actor class:

`void Apb_actorArray::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);

	if (ConnectionSocket)
	{
		ConnectionSocket->Close();
		ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ConnectionSocket);
		UE_LOG(LogTemp, Warning, TEXT("Connection closed."));
	}
}

`

I know its getting it’s way to the close because the log message prints.

Am I missing something?

Once I have started the game from the editor, any IP/port combo used are lost at game end. I either have to change the IP/port or restart the editor.

I’ll have to try and repro this at some point, but don’t have any time right now. Have you tried creating the socket as ‘reusable’ as a workaround?

I’m having the same problem in 4.7.3. I’m closing TCP connections when the actor handling the connections is destroyed changing maps, but want to use the same connection settings with the same actor on the new map.In theory I should be able to do this since closing and destorying the connections on EndPlay should free up the same connections for the new map. Any progress replicating the error?

Hi,
I have the same problem with the Rama’s code. I think I solved in this way. My code is:

void AMyPlayerController::EndPlay(const EEndPlayReason::Type EndPlayReason) {

		Super::EndPlay(EndPlayReason);

		if (ConnectionSocket)
		{
			ConnectionSocket->Close();
			ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ConnectionSocket);


			UE_LOG(LogTemp, Warning, TEXT("ConnectionSocket closed."));
		}

		if (ListenerSocket)
		{
			ListenerSocket->Close();
			ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ListenerSocket);


			UE_LOG(LogTemp, Warning, TEXT("ListenerSocket closed."));
		}
}

I destroyed both the ConnectionSocket than the ListenerSocket.

Bye