select方法中如何处理SOCKET?

问题描述 投票:0回答:1

我在IBM docs中看到了这个示例,介绍了如何在服务器程序中使用

select
方法,我想要类似于Windows上的方法,而不使用
vector
unordered_map
,但我面临的问题是Windows 使用
SOCKET
作为套接字描述符,而 linux 使用
int
虽然我可以将 Windows 套接字转换为整数,但不建议这样做,并且套接字值大于
FD_SETSIZE
,也就是说 for 循环在到达之前结束服务器套接字描述符和该函数最终有点无用

int Server::handler()
{
    int iResult;
    timeval timeout;
    fd_set activeFdSet;
    fd_set readFdSet;
    FD_ZERO(&activeFdSet);
    FD_SET(serv_sock, &activeFdSet);
    printf("FD_SETSIZE=%d\n", FD_SETSIZE);
    // listen for incoming connections
    iResult = listen(serv_sock, SOMAXCONN);
    timeout.tv_sec = 5;
    timeout.tv_usec= 0;

    while (1)
    {
        readFdSet = activeFdSet;
        printf("\tCopied activefdset to readfdset\n");
        int res = select(FD_SETSIZE, &readFdSet, NULL,NULL,&timeout);

        for (int i=0;i<FD_SETSIZE; i++)
        {
            if (FD_ISSET(i , &readFdSet)) // check socket descriptor 
            {
                if (i == (int)serv_sock)
                {
                    // accept connections to the server 
                }
                else // client socket 
                {
                    // receive from client 
                }
            }
        }
    }
    return 0;
}

在 for 循环中处理服务器套接字而不使用

vector
或任何其他类似概念的最佳方法是什么

winsock winsock2
1个回答
2
投票

在非 Windows 平台上,套接字用文件描述符表示,文件描述符基本上是文件表的索引。这就是为什么您可以使用

int
套接字作为循环计数器。

但是,Windows 套接字的情况并非如此。

SOCKET
是实际内核对象的不透明句柄,因此您不能像您尝试那样使用
SOCKET
作为循环计数器。并且不要将它们投射到
int

你真的别无选择,只能将接受的套接字存储在数组或其他容器中,然后迭代它,特别是如果你希望代码可以跨平台移植,特别是如果你想处理超过

FD_SETSIZE
数量客户端数量(在这种情况下,您应该使用
(e)poll()
或其他异步套接字 I/O 机制而不是
select()
),例如:

int Server::handler()
{
    int iResult;
    timeval timeout;
    fd_set readFdSet;
    int maxFd;

    // listen for incoming connections
    iResult = listen(serv_sock, SOMAXCONN);
    timeout.tv_sec = 5;
    timeout.tv_usec= 0;

    while (1)
    {
        FD_ZERO(&readFdSet);
        FD_SET(serv_sock, &readFdSet);

        #ifdef WIN32
        maxFd = -1; // not used on Windows
        #else
        maxFd = serv_sock;
        #endif

        for (each client_sock in list)
        {
            FD_SET(client_sock, &readFdSet);
            #ifndef WIN32
            if (client_sock > maxFd) maxFd = client_sock;
            #endif
        }
        #endif

        int res = select(maxFd+1, &readFdSet, NULL, NULL, &timeout);
        if (res < 0) ... // error handling as needed...

        if (FD_ISSET(serv_sock, &readFdSet)) 
        {
            // accept connections to the server, add to clients list 
        }

        for (each client_sock in list)
        {
            if (FD_ISSET(client_sock, &readFdSet)) // check socket descriptor 
            {
                // receive from client 
            }
        }
    }

    return 0;
}

话虽如此,仅在 Windows 上,您可以依赖 Microsoft 记录的实现细节,即

fd_set
具有
fd_count
fd_array[]
成员,因此您可以直接迭代
fd_set
的内部数组,例如:

int Server::handler()
{
    int iResult;
    timeval timeout;
    fd_set readFdSet;
    int maxFd;

    // listen for incoming connections
    iResult = listen(serv_sock, SOMAXCONN);
    timeout.tv_sec = 5;
    timeout.tv_usec= 0;

    while (1)
    {
        FD_ZERO(&readFdSet);
        FD_SET(serv_sock, &readFdSet);

        #ifdef WIN32
        maxFd = -1; // not used on Windows
        #else
        maxFd = serv_sock;
        #endif

        for (each client_sock in list)
        {
            FD_SET(client_sock, &readFdSet);
            #ifndef WIN32
            if (client_sock > maxFd) maxFd = client_sock;
            #endif
        }
        #endif

        int res = select(maxFd+1, &readFdSet, NULL, NULL, &timeout);
        if (res < 0) ... // error handling as needed...

        #ifdef WIN32
        for (int i = 0; i < readFdSet.fd_count; ++i)
        #else
        for (int client_sock = 0; client_sock <= maxFd; ++client_sock)
        #endif
        {
            #ifdef WIN32
            SOCKET client_sock = readFdSet.fd_array[i];
            #else
            if (!FD_ISSET(client_sock, &readFdSet)) // check socket descriptor
                continue;
            #endif
            if (client_sock == serv_sock)
            {
                // accept connections to the server, add to clients list 
            }
            else // client socket 
            {
                // receive from client 
            }
        }
    }

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.