0
votes

I use a blocking FSocket in client-side that connected to tcp server, if there's no message from server, socket thread would block in function FScoket::Recv(), if TCP server shutdown, socket thread is still blocking in this function. but when use blocking socket of BSD Socket API, thread would pass from recv function and return errno when TCP server shutdown, so is it the defect of FSocket?

uint32 HRecvThread::Run()
{
    uint8* recv_buf = new uint8[RECV_BUF_SIZE];

    uint8* const recv_buf_head = recv_buf;
    int readLenSeq = 0;

    while (Started)
    {
        //if (TcpClient->Connected() && ClientSocket->GetConnectionState() != SCS_Connected)
        //{
        //  // server disconnected
        //  TcpClient->SetConnected(false);
        //  break;
        //}

        int32 bytesRead = 0;
        //because use blocking socket, so thread would block in Recv function if have no message
        ClientSocket->Recv(recv_buf, readLenSeq, bytesRead);

        .....

        //some logic of resolution for tcp msg bytes

        .....
    }

    delete[] recv_buf;
    return 0
}
2
Don't call it when server is not responded with successIvan Aksamentov - Drop
@Drop How exactly can he discover that the server didn't respond with success without trying to receive a response?user207421
I mean that after client connect to server with success, then shutdown server manually.Protoss
@EJP Sorry for sloppy wording. You need to call this in UE API: FSocket::HasPendingData() before trying to read from it. Despite it's name FSocket is not really a socket wrapper, it's more high-level entity convenient for simple gamedev applications.Ivan Aksamentov - Drop
@Protoss Show us your code anyway. Maybe there is really something wrong with it or with UE.Ivan Aksamentov - Drop

2 Answers

1
votes

As I expected, you are ignoring the return code, which presumably indicates success or failure, so you are looping indefinitely (not blocking) on an error or end of stream condition.

NB You should allocate the recv_buf on the stack, not dynamically. Don't use the heap when you don't have to.

0
votes

There is a similar question on the forums in the UE4 C++ Programming section. Here is the discussion:

https://forums.unrealengine.com/showthread.php?111552-Recv-function-would-keep-blocking-when-TCP-server-shutdown

Long story short, in the UE4 Source, they ignore EWOULDBLOCK as an error. The code comments state that they do not view it as an error.

Also, there are several helper functions you should be using when opening the port and when polling the port (I assume you are polling since you are using blocking calls)

  • FSocket::Connect returns a bool, so make sure to check that return value.
  • FSocket::GetLastError returns the UE4 Translated error code if an error occured with the socket.
  • FSocket::HasPendingData will return a value that informs you if it is safe to read from the socket.
  • FSocket::HasPendingConnection can check to see your connection state.
  • FSocket::GetConnectionState will tell you your active connection state.

Using these helper functions for error checking before making a call to FSocket::Recv will help you make sure you are in a good state before trying to read data. Also, it was noted in the forum posts that using the non-blocking code worked as expected. So, if you do not have a specific reason to use blocking code, just use the non-blocking implementation.

Also, as a final hint, using FSocket::Wait will block until your socket is in a desirable state of your choosing with a timeout, i.e. is readable or has data.