【问题标题】:How to check if a given file descriptor stored in a variable is still valid?如何检查存储在变量中的给定文件描述符是否仍然有效?
【发布时间】:2012-09-02 16:05:52
【问题描述】:

我有一个文件描述符存储在变量 var 中。如何在以后检查该描述符是否有效?

  fdvar1= open(.....);
  fdvar2 = fdvar1;       // Please ignore the bad design

  ....
  // lots of loops , conditionals and threads. It can call close(fdvar2) also.  
  ....

  if(CheckValid(fdvar1)) // How can I do this check  ?
    write(fdvar1, ....);

现在我想检查 var1(仍然保存打开的描述符)是否仍然有效。 有任何 API 吗?

【问题讨论】:

  • 为什么FD是在C级而不是OS级复制?
  • 查看dup的手册页。
  • 即使你可以检查有效性,结果也大多是毫无价值的,因为有可能另一个打开的文件在关闭原始文件后收到相同的描述符。
  • 这在 TLPI 练习 5.4 中提到的很清楚。

标签: c linux gcc file-descriptor


【解决方案1】:

fcntl(fd, F_GETFD) 是检查fd 是否是有效的打开文件描述符的最便宜的规范方法。如果您需要批量检查很多,使用具有零超时的poll 并将events 成员设置为0,并在返回后检查revents 中的POLLNVAL 效率更高。

话虽如此,“检查给定资源句柄是否仍然有效”的操作几乎总是从根本上不正确。释放资源句柄后(例如 fd 为 closed),它的值可能会重新分配给您分配的下一个此类资源。如果有任何剩余的引用可能被使用,它们将错误地对新资源而不是旧资源进行操作。因此,真正的答案可能是:如果您还不知道程序的逻辑,那么您有重大的基本逻辑错误需要修复。

【讨论】:

  • @R 假设我正在尝试实现一个处理 FD 的库,例如管道库,并且我是将 FD 参数传递给将使用我的库的程序的人测试FD验证仍然是不好的做法?还是强制性的?
  • @petric:我不明白你的问题。作为一般性答案,我会说是的,“测试 FD 验证”很糟糕(而且毫无意义),但是如果您对自己在做什么有特别的担忧,您可能应该发布一个新问题来询问它(并且参考这个问题/答案)而不是在评论中提问。
  • 如果我有父子进程共享一个管道怎么办。在父进程中,我关闭管道的读取端和写入端。那么子进程仍然有一个有效的读端。这是如何工作的?
  • @HelpingBean:我看不出这与这个问题有什么关系。如果您在那里有真正的问题,请将其作为新问题发布(并随时在此处@我并提供指向新问题的链接)。
  • 这很有趣。但如果我对包含一些文件描述符的结构进行单元测试。我想测试一个关闭文件描述符并回收内存的函数。在这种情况下检查文件描述符是否关闭是否正确?
【解决方案2】:

你可以使用fcntl()函数:

int fd_is_valid(int fd)
{
    return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}

【讨论】:

  • F_GETFD 原则上更便宜,因为它只取消引用内核空间中的(进程本地)文件描述符,而不是它所引用的底层打开文件描述(进程共享)。
  • 您应该在调用fcntl 之前将errno 设置为零。 errno 在调用函数之前可以等于 EBADFfcntl 只会在出现错误时更改它。
  • @Bilow 他已经在检查-1 的返回值,这只会在“出现错误的情况下”发生,因此在调用之前将errno 设置为0 将是多余的。
  • @CraigBarnes 确实
【解决方案3】:

来自this论坛文章:

int is_valid_fd(int fd)
{
    return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
}

fcntl(GETFL) 可能是最便宜且最不可能失败的 您可以对文件描述符执行的操作。特别是, 规范表明它不能被信号打断,也不能 它是否受到任何地方持有的任何类型的锁的影响。

【讨论】:

【解决方案4】:

我认为没有任何函数可以告诉您描述符是否仍然有效。描述符通常只是一个像 6 这样的小整数,如果您关闭文件并稍后打开一个新文件,您的 libc 可以选择重用该数字。

相反,您应该考虑使用dup() 来复制文件描述符。通过复制文件描述符而不是在多个位置使用相同的描述符,您可能会更容易知道文件描述符是否仍然有效。您只需要记住在完成后关闭原始描述符和复制的描述符。

【讨论】:

  • David 是“正确的”,因为您无法确定描述符是否“仍然有效”。您可以判断它是否有效,但这不会为您提供有关它是否仍然引用同一资源的信息。
  • 是的。我对有效的定义是它仍然指向与以前相同的东西。我认为这是一个很好的定义,因为它通常是您想要的,您可以通过查看代码来判断描述符是否仍然有效;它不依赖于未定义的行为。
  • 另外,使用dup 是一个不错的建议对于 OP 的特定问题。它将避免整个问题。更好的方法可能是在一个单独的变量中保留一个标志,指示文件描述符是否已经关闭;这将避免额外的内核空间之旅(以及稀缺的资源消耗)。
  • 大家好,我更新了我的答案(超过 2 年)以更清晰。我并不是建议您调用dup 只是为了查看文件描述符是否有效;我试图提供一些设计建议,以便一开始就更容易避免这种情况。
【解决方案5】:

在我看来,如果你想知道它是否仍然指向同一个资源,一种(非完美)方法是在打开之后使用fstat() 描述符,然后你可以再做一次并比较结果。从查看.st_mode& S_IFMT 开始,然后从那里开始——它是一个文件系统对象吗?看.st_dev / .st_ino.是socket吗?试试getsockname()getpeername()。它不会 100% 确定,但它可以告诉你它是否绝对不一样。

【讨论】:

    【解决方案6】:

    我为我解决了这个问题。我不知道它是否可以用于一般用途,但对于串行连接它工作正常(例如/dev/ttyUSB0)!

    struct stat s;
    fstat(m_fileDescriptor, &s);
    
    // struct stat::nlink_t   st_nlink;   ... number of hard links 
    if( s.st_nlink < 1 ){
     // treat device disconnected case
    }
    

    有关详细信息,请参阅例如手册页http://linux.die.net/man/2/fstat

    干杯, 弗洛尔

    【讨论】:

      猜你喜欢
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      • 2014-05-02
      • 2021-05-08
      • 1970-01-01
      • 1970-01-01
      • 2013-11-08
      • 2016-04-18
      相关资源
      最近更新 更多