Windows上的C中到底如何处理套接字?

9wbgstp7  于 2023-10-16  发布在  Windows
关注(0)|答案(1)|浏览(95)

所以,我遇到了一个问题,我试图做一个简单的c服务器-客户端,基本上是一个客户端连接到服务器,时不时地服务器ping客户端,不应该这么复杂,但我遇到了一个奇怪的行为从“选择”,“发送”和“接收”。
服务器代码(没有整个连接部分)基本上是这样的:

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);
                        }
                    }
                }
            }
        }

    }

客户端代码(不包括连接部分)是:

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);
    }

我期望的行为是,每当客户端从recv阻塞时,服务器上的select返回write_set上的客户端套接字,服务器向客户端写入5个字节,读取5个字节,然后阻塞,直到下一个recv来自客户端。
但事实并非如此,在第一次recv之后,服务器继续写入5个字节,它正确地接收到“PONG”,但并没有停止向客户端写入。

我知道它正在向客户端写入,因为当我杀死客户端进程时,发送立即失败。
Windows是不是很奇怪?我是不是不知道如何使用select?在第一次接收后,客户端如何告诉服务器它没有达到阅读?

hs1rzwqc

hs1rzwqc1#

.,每当客户端从recv阻塞时,服务器上的select返回write_set上的客户端套接字,服务器向客户端写入5个字节,读取5个字节,
如果客户端等待recv中的数据,则不会向服务器发送任何类型的通知。在一侧的send和另一侧的recv之间没有其他紧耦合。recvsendselect都只在socket的发送和接收缓冲区上工作:

  • recv将从套接字接收缓冲区返回数据。请注意,如果缓冲区中没有那么多数据,它可能不会返回所有请求的数据,因此请检查返回值以了解实际读取了多少数据。如果缓冲区中没有数据,它将阻塞,直到操作系统接收到这些数据并将其放入缓冲区。
  • 如果sockets send buffer中有足够的空间来放置新数据,send将返回-无论对等体当前是否正在调用recv。请注意,可能没有足够的空间容纳所有数据,因此您需要检查send返回的内容,以了解实际上有多少数据被放入发送缓冲区。如果缓冲区中没有空间,send将阻塞,并等待操作系统通过将数据发送到对等体来腾出一些空间。
  • select将返回一个套接字可读,如果有任何数据在套接字接收缓冲区。
  • 如果sockets send buffer中有用于新数据的空间,select将返回一个sockets作为可写

相关问题