首页 > 解决方案 > 如何让服务器在第一个客户端后不等待接受?

问题描述

我有一个 tcp 服务器,我想制作它,所以在它接受第一个客户端后,它不会等待接受函数,如果没有其他人连接,它就会继续

while (1)
    {

        SOCKET ClientSocket = accept(Socket, (sockaddr *)&Client, &ClientSize);
        if(ClientSocket == INVALID_SOCKET)
        {
            Error("accept failed.\n");
        }
        ClientSockets[ClientSocketsIndex++] = ClientSocket;

        Result = connect(ClientSocket, (sockaddr*)&Client, ClientSize);
    
        sockaddr_in From;
        int FromSize = sizeof(From);
        Result = recv(ClientSocket, Message, sizeof(Message), 0);
        
        if (Result == SOCKET_ERROR)
        {
            Error("recv failed.\n");
        }
        
        Result2 = getpeername(ClientSocket, (sockaddr*)&From, &FromSize);
        if (Result2 == SOCKET_ERROR)
        {
            Error("getpeername failed.\n");
        }

在这里,我使用 ClientSocketaccept()并将其添加到存储所有 ClientSocket 的数组中,然后接收缓冲区。问题是在每个循环之后它都会等待一个新的 ClientSocket。

Error()功能只是我为打印到控制台并在遇到错误 btw 时退出的功能。

标签: cwinapinetwork-programming

解决方案


首先,调用connect()return SOCKETbyaccept()是错误的。摆脱它。

其次,如果您希望您的循环正确地为多个客户端提供服务,请使用select()(或等效)。在告诉您新客户正在等待接受accept()之前不要打电话。同样,在告诉您阵列中的客户端正在等待读取之前select()不要打电话。recv()select()

尝试更多类似的东西:

const size_t MAX_SOCKETS = ...;

SOCKET ClientSockets[MAX_SOCKETS];
size_t NumClientSockets = 0;

...

while (true)
{
    fd_set readfds;
    FD_ZERO(&readfds);

    FD_SET(Socket, &readfds);
    for(int i = 0; i < NumClientSockets; ++i)
    {
        FD_SET(ClientSockets[i], &readfds);
    }

    if (select(0, &readfds, NULL, NULL, NULL) > 0)
    {
        if (FD_ISSET(Socket, &readfds))
        {
            ClientSize = sizeof(Client);
            SOCKET ClientSocket = accept(Socket, (sockaddr *)&Client, &ClientSize);
            if (ClientSocket == INVALID_SOCKET)
            {
                Error("accept failed.\n");
            }
            else if (NumClientSockets == MAX_SOCKETS)
            {
                closesocket(ClientSocket);
            }
            else
            {
                ClientSockets[NumClientSockets] = ClientSocket;
                ++NumClientSockets;
            }
        }

        size_t i = 0;
        while (i < NumClientSockets)
        {
            if (!FD_ISSET(ClientSockets[i], &readfds))
            {
                ++i;
                continue;
            }

            Result = recv(ClientSockets[i], Message, sizeof(Message), 0);
            if (Result <= 0)
            {
                if (Result == SOCKET_ERROR)
                    Error("recv failed.\n");

                for(size_t j = i + 1; j < NumClientSockets; ++j)
                {
                    ClientSockets[j - 1] = ClientSockets[j];
                }
                --NumClientSockets;

                continue;
            }

            // use Message up to Result bytes as needed...

            ++i;
        }
    }
}

推荐阅读