FSocket - How to handle client disconnection

I am able to start a server and receive data from client. I am running in a loop to get data from socket receive buffer and all is working fine until client closes socket, I am not able to handle this.

I am reading data from the client using the following line:

ConnectionSocket->Recv(ReceivedData.GetData(), BytesToRead, Read, ESocketReceiveFlags::WaitAll);

When a client disconnects, it crashes when calling this function.
Any tips on how to avoid crash when client disconnects? Is there a way of checking for client connection before trying to read from it?

Make sure to call ConnectionSocket->HasPendingData(DatagramSize) before, this function will return if data is there, if not your socket is disconnected. It is typically called like the following pseudo code:

while (sock->HasPendingData(...))
{
    if (Socket->RecvFrom(...))
    {
        // handle incoming data
    }
}

But what if a client is connected, but haven’t written data, then sock->HasPendingData(…) returns false although the client might still be connected.

What I was opting for was to use sock->RecvFrom to block until the specified amount of bytes were read, or the socket closed, hence using the WaitAll flag.

In the documentation this flag should wait until the data was read, or the socket close.

Ok, you can check the socket state if it’s connected or not:

if (Socket->GetConnectionState() != SCS_Connected)
{
    // Socket disconnected, remove from list of connected sockets?
}

Thanks, but does not seem to work. I always seem to crash either way, using this code :

while(shouldReceiveData == true){
    if (Socket->GetConnectionState() != SCS_Connected){
         // Socket disconnected, remove from list of connected sockets?
     }else{
         aSocket->Recv(Data, MaxBuffer, BytesRead);
    }
 }

I stopped using the WaitAll flag btw. It works fine until I disconnect the client. Any tips on how to handle the general case of a client disconnecting?

Even if the socket state is != from SCS_Connected it does not mean that you can safely call Recv, you have to check for HasPendingData always.

The following code is what I do on a thread:

while (!Stopping)
	{
		// Add all clients that connected in the last tick
		if (!PendingClients.IsEmpty())
		{
			FSocket *Client = NULL;
			while (PendingClients.Dequeue(Client))
			{
				Clients.Add(Client);
			}
		}

		// Remove closed connections
		for (int32 ClientIndex = Clients.Num() - 1; ClientIndex >= 0; --ClientIndex)
		{
			if (Clients[ClientIndex]->GetConnectionState() != SCS_Connected)
			{
				Clients.RemoveAtSwap(ClientIndex);
			}
		}

		// Poll data from every connected client
		for (TArray<class FSocket*>::TIterator ClientIt(Clients); ClientIt; ++ClientIt)
		{
			FSocket *Client = *ClientIt;
			uint32 DataSize = 0;
			while (Client->HasPendingData(DataSize))
			{
				FString Request;
				if (RecvMessage(Client, DataSize, Request))
				{
					FString Response = HandleClientMessage(Client, Request);
					SendMessage(Client, Response);
				}
			}
		}
	}

RecvMessage and SendMessage are just wrappers to the normal send and recv calls.

Have you been able to progress on your issue?

Hi, sorry about the late replies! havnt really had time to work on this issue, but I will implement your solution when I do have the time

For me ConnSocket->GetConnectionState() is always ESocketConnectionState::SCS_Connected even if the client disconnects

I’ve a similar problem, it crashes in: while(socket->HasPendingData()){…} everytime i disconnect.

What connection state do you get?

Is there anything that might be null in ConnSocket?