【问题标题】:Understanding a Select loop for receiving UDP messages and opening TCP sockets了解用于接收 UDP 消息和打开 TCP 套接字的 Select 循环
【发布时间】:2012-12-05 20:01:45
【问题描述】:

您好,我正在为网络类工作一个项目,我们正在网络中创建节点,这些节点通过 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?
    }

}

【问题讨论】:

    标签: c sockets networking tcp udp


    【解决方案1】:

    创建侦听 TCP 套接字(socket(2)bind(2)listen(2))后,用setsockopt(2) 将其标记为非阻塞,并将其添加到select(2) 的读取集中。

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

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

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

    【讨论】:

      【解决方案2】:

      在调用FD_SET()select() 之前,您需要在每次循环迭代中调用FD_ZERO()。此外,在您首先尝试连接它之前,不要将 TCP 套接字添加到 fd_set。保留您创建的 TCP 套接字列表,以便在每次循环迭代时将它们重新添加到 fd_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);
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2017-09-04
        • 1970-01-01
        • 1970-01-01
        • 2021-01-23
        • 2023-04-03
        • 2015-12-12
        • 2018-04-03
        • 2015-01-02
        • 1970-01-01
        相关资源
        最近更新 更多