开发者

C++ select stops accepting connections

I'm trying to make a select-server in order to receive connection from several clients (all clients will connect to the same port).

The server accepts the first 2 clients, but unless one of them disconnects, it will not accept a new one. I'm starting to listen the the server port like this:

listen(m_socketId, SOMAXCONN);  

and using the select command like this:

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

I've added some code.

bool TcpServer::Start(char* ipAddress, int port)
{
    m_active = true;
    FD_ZERO(&m_socketMasterSet开发者_StackOverflow);
    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;
}

I hope it's enough :) what's wrong with it?


The by far most common error with select() is not re-initializing the fd sets on every iteration. The second, third, and forth arguments are updated by the call, so you have to populate them again every time.

Post more code, so people can actually help you.

Edit 0:

fd_set on Windows is a mess :)


It's not allowed to copy construct fd_set objects:

 m_socketReadSet = m_socketMasterSet;

This combined with Nikolai's correct statement that select changes the set passed in probably accounts for your error.

poll (On Windows, WSAPoll) is a much friendlier API.

Windows also provides WSAEventSelect and (Msg)WaitForMultipleObjects(Ex), which doesn't have a direct equivalent on Unix, but allows you to wait on sockets, files, thread synchronization events, timers, and UI messages at the same time.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜