代码之家  ›  专栏  ›  技术社区  ›  Michael Kohne

UDP套接字上的选择在套接字关闭时不会结束-我做错了什么?

  •  8
  • Michael Kohne  · 技术社区  · 17 年前

    我在Linux系统上工作(Ubuntu 7.04服务器,内核为2.6.20)。

    从另一个线程,我关闭并关闭套接字。 如果在thread1在recvfrom中被阻塞时执行此操作,则recvfrom将立即终止。 如果我在thread1被阻塞在带有超时的select中时执行此操作,则select不会立即终止,但最终会正确超时。

    有人能告诉我为什么插座一关闭,select就不退出吗?这不是个例外吗?我可以看到它不可读的地方(很明显),但它是封闭的,这似乎是例外。

    下面是套接字的开始(删除所有错误处理以保持简单):

    m_sockfd = socket(PF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in si_me;
    memset((char *) &si_me, 0, sizeof(si_me));
    si_me.sin_family = AF_INET;
    si_me.sin_port = htons(port);
    si_me.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(m_sockfd, (struct sockaddr *)(&si_me), sizeof(si_me)) < 0)
    {
    // deal with error
    }
    

    以下是thread1执行的select语句:

    struct timeval to;
    to.tv_sec = timeout_ms/1000;// just the seconds portion
    to.tv_usec = (timeout_ms%1000)*1000;// just the milliseconds 
                                        // converted to microseconds
    
    // watch our one fd for readability or
    // exceptions.
    fd_set  readfds, exceptfds;
    FD_ZERO(&readfds);
    FD_SET(m_sockfd, &readfds);
    FD_ZERO(&exceptfds);
    FD_SET(m_sockfd, &exceptfds);
    
    int nsel = select(m_sockfd+1, &readfds, NULL, &exceptfds, &to);
    

    我真的很想了解这种选择行为背后的想法,因为它似乎与我的期望背道而驰。因此,我显然需要调整我对TCP堆栈如何工作的想法。请给我解释一下。

    6 回复  |  直到 17 年前
        1
  •  4
  •   iny    17 年前

    也许你应该用别的东西来唤醒选择。也许是烟斗之类的。

        2
  •  4
  •   John Zwinck    17 年前

    UDP是一种无连接协议。因为没有连接,没有一个可以断开,所以消费者不知道制作人再也不会发送了。

    您可以让生产者发送一条“流结束”消息,并让消费者在收到该消息后终止。

        3
  •  3
  •   Richard Whitty    17 年前

    您能否向线程发送一个信号(例如USR2),该信号将导致select()返回EINTR?

    这将消除等待多个文件描述符的需要,而且似乎比使用管道杀死它要干净得多。

        4
  •  2
  •   a2800276    17 年前

    我认为最明显的解决办法是关闭不被视为例外情况。我认为问题的根源在于,你并没有真正接受 select . 你究竟为什么要摆弄另一条线中的插座,这听起来像是灾难的秘诀。

        5
  •  2
  •   Rob K    17 年前

    我想说的是,不同之处在于recvfrom正在积极尝试从单个套接字读取消息,其中select正在等待消息到达,可能在多个句柄上,而不一定是套接字句柄。

        6
  •  0
  •   David Schwartz    9 年前

    你的代码从根本上被破坏了。这种错误的变体是常见的,并且在过去已经导致了严重的错误,具有巨大的安全隐患。以下是您缺少的内容:

    当您关闭套接字时,根本无法知道另一个线程是否被阻塞 select 或者就要堵进去 选择 . 例如,考虑以下内容:

    1. 选择
    2. 你把插座合上。
    3. 在代码不知道的线程中(可能是平台内部内存管理或日志记录内部的一部分),库打开套接字并获得与关闭的套接字相同的标识符。
    4. 选择 ,但它是 选择 在库打开的套接字上打开。
    5. 灾难来袭。

    当另一个线程正在或可能正在使用某个资源时,不得尝试释放该资源。