cwindowssocketswinsock2

How exactly sockets are handled in C on windows?


So, I'm having a problem, I'm trying to do a simple c server-client, where basically a client connects to the server, and from time to time the server pings the client, shouldn't be this complicated, but I'm being met with a strange behaviour from both "select", "send" and "recv".

The server code is (without the whole connection part) basically this:

while (1) {
        read_set = set; write_set = set; error_set = set; timeout = ref_timeout;
        int result = select(NULL, &read_set, &write_set, &error_set, &timeout); //I'm on windows that's why the first parameter is null
        if (result < 0) {
            puts("Error select");
            return 1;
        }
        if (result == 0) puts("timed out");
        else {
            for (int index = 0; index < 2; index++) {
                SOCKET i = sockets[index];
                if (FD_ISSET(i, &error_set)) {
                    printf("%zu error\n", i);
                    FD_CLR(i, &set);
                    closesocket(i);
                }

                if (FD_ISSET(i, &write_set)) {
                    const char* ping = "PING";
                    int size = send(i, ping, strlen(ping)+1, 0);
                    printf("%d bytes sent\n", size);
                    if (size < 0) {
                        puts("Error send");
                        closesocket(i);
                        FD_CLR(i, &set);
                    }
                    send(i, NULL, 0, 0);
                }

                if (FD_ISSET(i, &read_set)) {
                    if (i == listen_socket){
                        struct sockaddr addr;
                        int addrlen;
                        SOCKET new_socket = accept(listen_socket, &addr, &addrlen);
                        FD_SET(new_socket, &set);
                        if (new_socket > biggest) biggest = new_socket;
                        printf("new conn %zu\n", new_socket);
                        sockets[1] = new_socket;
                    }
                    else {
                        char msg[100];
                        memset(msg, 0, sizeof(msg));
                        if (recv(i, msg, sizeof(msg), 0) < 0) {
                            closesocket(i);
                            FD_CLR(i, &set);
                        }
                        else {
                            printf("%zu %s\n", i, msg);
                        }
                    }
                }
            }
        }

    }

And the client code (without the connection part) is:

    char buffer[100];
    const char* pong = "PONG";
    for (int i = 0; i < 3; i++) {
        memset(buffer, 0, sizeof(buffer));
        int result = recv(client_socket, buffer, sizeof(buffer), 0);
        if (result < 0) {
            puts("something went wrong receiving");
            closesocket(client_socket);
            return 1;
        }
        if (send(client_socket, pong, strlen(pong)+1, 0) < 0) {
            puts("something went wrong sending");
            return 1;
        }
        printf("msg: %s\n", buffer);
        Sleep(10000);
    }

The behaviour I would expect is, whenever the client block from recv, the select on the server returns with the client socket on the write_set, the server writes the 5 bytes to the client, reads the 5 bytes, and then blocks until the next recv from the client.

But that's not what's happening, after the first recv, the server keeps writing 5 bytes, it receives "PONG" correctly, but doesn't stop writing to the client.

Output

And I know it is writing to the client because when I kill the client process the send immediately fails.

Is this windows being weird? Am I not understanding how to use select? How can the client tell the server it's not up to reading after the first recv?


Solution

  • ..., whenever the client block from recv, the select on the server returns with the client socket on the write_set, the server writes the 5 bytes to the client, reads the 5 bytes,

    There is no kind of notification to the server if the client waits for data in recv. There is no other tight coupling between send on one side and recv on the other.recv, send and select all only work on the send and receive buffers of the socket: