【问题标题】:How to make server not wait on accept after first client?如何让服务器在第一个客户端后不等待接受?
【发布时间】:2020-11-27 10:22:20
【问题描述】:

我有一个 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");
        }

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

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

【问题讨论】:

  • 也许,您怀疑Result = connect(ClientSocket, ... 在这种情况下实际上在做什么?您已经拥有一个连接到您的客户端的套接字;这是从accept 返回的内容。
  • 嗯.. ..将accept()移到while循环上方?
  • @MartinJames 但如果我不知道有多少用户要连接,我将如何接受正确的数量?
  • @WhozCraig 谢谢,我之前在调试某些东西时忘记删除它,并认为这会解决它。
  • 猜测一下,您提出的问题和您需要解决的真正问题并不是一回事。据推测,您不希望您的 accept 呼叫被阻止,因为您需要完成其他工作。如果是这种情况,请改用 Windows Sockets 的异步接口(例如AcceptEx)。 Getting Started with Winsock 列出示例代码资源。 iocpoverlap 类别是您正在寻找的。​​span>

标签: c winapi network-programming


【解决方案1】:

首先,在accept() 返回的SOCKET 上调用connect() 是错误的。摆脱它。

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

试试这样的:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-27
    • 1970-01-01
    • 1970-01-01
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 2015-02-14
    相关资源
    最近更新 更多