C++ select 停止接受连接

发布于 2024-11-09 10:06:29 字数 2381 浏览 0 评论 0原文


我正在尝试创建一个选择服务器,以便接收来自多个客户端的连接(所有客户端将连接到同一端口)。
服务器接受前 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;
}

我希望这已经足够了:) 有什么问题吗?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

客…行舟 2024-11-16 10:06:29

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

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

编辑0:

fd_set 在 Windows 上是一团糟:)

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 :)

无言温柔 2024-11-16 10:06:29

不允许复制构造 fd_set 对象:

 m_socketReadSet = m_socketMasterSet;

这与 Nikolai 的正确声明相结合,select 更改传入的集合可能会导致您的错误。

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文