2

嗨,我正在为网络类工作一个项目,我们正在网络中创建节点,这些节点通过 udp 从控制应用程序接收消息,然后与其他节点创建 tcp 连接。基本顺序如下: 1) 控制管理器向节点 A 发送 udp 消息,告诉它连接到节点 B 2) 节点 A 接收到 udp 消息并将 udp 消息转发给节点 B 3) 节点 B 接收到 udp 消息,随机选择一个端口号,在该端口上打开一个侦听 tcp 套接字,并使用端口号将 udp 消息发送回 A 4) 节点 A 接收到 udp 消息并在该 tcp 端口上打开与节点 B 的连接。

基本上,我想循环接收到的 udp 消息并跳转到我的消息解析函数,同时循环 tcp 连接。这部分看起来很简单,但我真的不明白如何将监听套接字添加到文件描述符列表中。以下代码是我放在一起的,我想知道基本结构是否正确?我真的不明白如何创建监听 tcp 套接字并将其添加到 fd 列表中?

SOCKET udpsock;
udpsock = initudp(port); //setup udp socket
SOCKET tcpsock;
FD_ZERO(&rdsocks);

max = udpsock + 1;
while(1)
{
    SOCKET temp;

    FD_SET(udpsock,&rdsocks);//setup udp macros
    FD_SET(tcpsock,&rdsocks);

    if( select(max,&rdsocks,NULL,NULL,NULL) == SOCKET_ERROR )
    {
        perror("Select error");
        WSACleanup();
        return 1;
    }
    for(temp = 0; temp<=max;temp++) // loop on TCP sockets
    {
        if(FD_ISSET(temp,&rdsocks))
        {
            printf("Socket %d is ready \n",temp);
            // process tcp messages
        }

    }
    if(FD_ISSET(udpsock,&rdsocks)) // udp connection, parse control message
    {
        int ret = 0;
        res = recvfrom(udpsock, buff,sizeof(buff),0,(struct sockaddr*)&udpclient,lenaddr);
        //process udp message, setup tcp connection here if requested and add to file descriptor list?
    }

}
4

2 回答 2

2

创建侦听 TCP 套接字 ( socket(2), bind(2), listen(2)) 后,将其标记为非阻塞setsockopt(2),并将其添加到select(2).

当它变得“可读”时,这意味着您有客户端连接挂起,请致电accept(2). 也将新连接的套接字添加到读取集中。

您可能希望保留这些客户端套接字的列表/哈希/任何内容,因为必须在每次调用之前重新初始化读取集select(2)并计算其第一个参数(最大 fd)。

注意 0:我在这里参考 Linux 手册页,但逻辑几乎是跨平台的。您可以在MSDN上找到 Windows 参考资料。 注 1:Windowsselect()忽略它的第一个参数。

于 2012-12-05T20:18:14.037 回答
1

您需要在调用andFD_ZERO()之前调用每个循环迭代。此外,在您首先尝试连接它之前,不要将 TCP 套接字添加到它。保留您创建的 TCP 套接字列表,以便您可以将它们重新添加到每次循环迭代中。FD_SET()select()fd_setfd_set

尝试这样的事情:

udpsock = initudp(port); //setup udp socket

std::vector<SOCKET> tcpsocks;
SOCKET tcpsock;

while(1)
{
    FD_ZERO(&rdsocks);
    FD_SET(udpsock, &rdsocks);
    max = udpsock;

    for(size_t i = 0; i < tcpsocks.size(); ++i)
    {
        tcpsock = tcpsocks[i];
        FD_SET(tcpsock, &rdsocks);

        if( tcpsock > udpsock )
            max = tcpsock;
    }

    if( select(max+1, &rdsocks, NULL, NULL, NULL) == SOCKET_ERROR )
    {
        perror("Select error");
        WSACleanup();
        return 1;
    }

    for(size_t i = 0; i < tcpsocks.size(); ++i) // loop on TCP sockets
    {
        tcpsock = tcpsocks[i];            
        if( FD_ISSET(tcpsock, &rdsocks) )
        {
            printf("Socket %d is ready \n", tcpsock);
            // process tcp message
        }
    }

    if( FD_ISSET(udpsock, &rdsocks) )
    {
        int ret = 0;
        res = recvfrom(udpsock, buff, sizeof(buff), 0, (struct sockaddr*)&udpclient, lenaddr);
        // process udp message...
        if( setup tcp connection is requested )
        {
            tcpsock = ...;
            if( tcpsock != INVALID_SOCKET )
                tcpsocks.push_back(tcpsock);
        }
    }
}
于 2012-12-06T02:01:55.557 回答