0

I am building an application that uses Windows sockets for communication. The Client class handles the connection and spawns a thread that should periodically check if the connection is alive and if it's not, it should try to reconnect.

bool Client::Connect() {
    fSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, NULL, NULL);
    if (WSAConnect(fSocket, (SOCKADDR*) &fAddress, sizeof(fAddress), nullptr, nullptr, nullptr, nullptr) != 0) {
        return false;
    }
    return true;
}

void Client::StartConnectionAndKeepAlive() {
    auto threadFunction = [this]() {
        while (true) {
            if (!this->fConnected) {
                this->CloseConnection();
                this->Connect();
                this->Send("Hello from thread!\n");
            }
            this_thread::sleep_for(chrono::seconds(1));
        }
    };
    fThread = new thread(threadFunction);
}

bool Client::Send(const string& data) {
    auto nBytesSent = send(fSocket, data.c_str(), int(data.size()), NULL);
    cout << "nBytesSent: " << nBytesSent << " for data: " << data << endl;
    if (nBytesSent == SOCKET_ERROR) {
        fConnected = false;
        return false;
    }
    fConnected = true;
    return true;
}

After instantiating Client, Client::StartConnectionAndKeepAlive() is called. If the connection is not possible, the value of send will be equal to SOCKET_ERROR as expected.

However my problem is when the server closes the connection (I am currently using netcat and close the connection just by ctrl+C). After closing the connection the return value of send is the same as when the connection is alive. This causes the flag fConnected to stay true and therefor the connection won't be restablished even if I launch netcat again.

This is the first time I am working with sockets and windows so I am surely mising something but I couldn't find a solution online. All similar question responses state that the return value of send should be SOCKET_ERROR if there is no connection (if I understood them correctly) but I found it's not the case.

I am aware that I should probably use std::mutex in my class since I am using it from multiple threads but found that adding it doesn't make my problem disappear, I removed them to keep the code simpler.

Any feedback to my implementation is also welcome! Thanks!

lobis
  • 145
  • 1
  • 10
  • https://stackoverflow.com/a/685981/1047662, I guess you could also use `WSAEventSelect` or `WSAWaitForMultipleEvents` to wait for a close event happening on the socket. – Cyclonecode Jul 23 '22 at 18:48
  • Thanks @Cyclonecode, I checked that answer before but for example the information stated in https://stackoverflow.com/a/686002/11776908 is incompatible with my experience unless I am missing something. I will take a closer look thanks. – lobis Jul 23 '22 at 18:52

1 Answers1

0

So it turns out the problem is related to netcat. I implemented a simple socket server using node.js and in fact the return value of send is SOCKET_ERROR after the connection is closed. However this does not happens when you close the netcat connection which was started with the nc -lvnp flags.

lobis
  • 145
  • 1
  • 10
  • 2
    A socket can't detect in a timely manner when the connection is lost *abnormally*, such as when killing the peer process. It can take several minutes for the OS to timeout internally and invalidate the connection locally. Until then, `send()` will happily keep buffering data normally. You have to turn on TCP keelaives, or use timeouts in your own code, to handle this. – Remy Lebeau Jul 23 '22 at 21:00