【问题标题】:C++ select stops accepting connectionsC++ 选择停止接受连接
【发布时间】:2011-05-23 03:19:22
【问题描述】:


我正在尝试创建一个选择服务器以接收来自多个客户端的连接(所有客户端都将连接到同一个端口)。
服务器接受前 2 个客户端,但除非其中一个断开连接,否则它不会接受新的客户端。 我开始像这样监听服务器端口:

listen(m_socketId, SOMAXCONN);  

并像这样使用选择命令:

int selected = select(m_maxSocketId + 1, &m_socketReadSet, NULL, NULL, 0);

我添加了一些代码。

bool TcpServer::Start(char* ipAddress, int port)
{
    m_active = true;
    FD_ZERO(&m_socketMasterSet);
    bool listening = m_socket->Listen(ipAddress, port);
    // Start listening.

    m_maxSocketId = m_socket->GetId();
    FD_SET(m_maxSocketId, &m_socketMasterSet);
    if (listening == true)
    {
        StartThread(&InvokeListening);
        StartReceiving();
        return true;
    }
    else
    {
        return false;
    }
}

void TcpServer::Listen()
{
    while (m_active == true)
    {
        m_socketReadSet = m_socketMasterSet;
        int selected = select(m_maxSocketId + 1, &m_socketReadSet, NULL, NULL, 0);
        if (selected <= 0)
            continue;
        bool accepted = Accept();
        if (accepted == false)
        {
            ReceiveFromSockets();
        }
    }
}

bool TcpServer::Accept()
{
    int listenerId = m_socket->GetId();
    if (FD_ISSET(listenerId, &m_socketReadSet) == true)
    {
        struct sockaddr_in remoteAddr;
        int addrSize = sizeof(remoteAddr);
        unsigned int newSockId = accept(listenerId, (struct sockaddr *)&remoteAddr, &addrSize);
        if (newSockId == -1) // Invalid socket...
        {
            return false;
        }
        if (newSockId > m_maxSocketId)
        {
            m_maxSocketId = newSockId;
        }

        m_clientUniqueId++;
        // Remembering the new socket, so we'll be able to check its state
        // the next time.
        FD_SET(newSockId, &m_socketMasterSet);

        CommEndPoint remote(remoteAddr);
        CommEndPoint local = m_socket->GetLocalPoint();

        ClientId* client = new ClientId(m_clientUniqueId, newSockId, local, remote);
        m_clients.Add(client);
        StoreNewlyAcceptedClient(client);
        char acceptedMsg = CommInternalServerMsg::ConnectionAccepted;
        Server::Send(CommMessageType::Internal, client, &acceptedMsg, sizeof(acceptedMsg));
        return true;
    }

    return false;
}

我希望这就足够了 :) 有什么问题?

【问题讨论】:

    标签: c++ windows sockets select


    【解决方案1】:

    到目前为止,select() 最常见的错误是没有在每次迭代时重新初始化 fd 集。第二、第三和第四个参数由调用更新,因此您必须每次再次填充它们。

    发布更多代码,以便人们可以真正帮助您。

    编辑0:

    fd_set 在 Windows 上是一团糟:)

    【讨论】:

      【解决方案2】:

      不允许复制构造 fd_set 对象:

       m_socketReadSet = m_socketMasterSet;
      

      这与 Nikolai 的正确陈述相结合,即 select 更改传入的集合可能是您的错误的原因。

      poll(在 Windows 上,WSAPoll)是一个更友好的 API。

      Windows 还提供了WSAEventSelect(Msg)WaitForMultipleObjects(Ex),它们在 Unix 上没有直接等价物,但允许您同时等待套接字、文件、线程同步事件、计时器和 UI 消息。

      【讨论】:

      • 好的,那么我该如何更新 FD_SET?我更喜欢使用“选择”以便与 unix 兼容。 :)
      • @ldov:有时会有一个FD_COPY 宏,但我认为VC++ 没有提供它。您需要保留一组套接字句柄,并为每个句柄循环调用FD_SET。此时您最好使用poll 和少量特定于操作系统的代码。尽管名称不同,WSAPollpoll 的工作方式完全相同,一直到参数的顺序。不幸的是,Windows select 无论如何都不能 100% 兼容 BSD 套接字。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-05
      • 1970-01-01
      • 1970-01-01
      • 2019-04-30
      • 2011-03-27
      • 1970-01-01
      • 2017-11-11
      相关资源
      最近更新 更多