【问题标题】:How can I detect when someone opens the slave side of a pty (pseudo-terminal) in Linux?如何检测何时有人在 Linux 中打开 pty(伪终端)的从属端?
【发布时间】:2010-08-15 06:42:13
【问题描述】:

从串行设备 (/dev/ttyXX) 读取多个进程会导致这两个进程无法获取所有数据——数据将以某种方式在它们之间拆分。我想编写一个从串行设备读取的程序,创建几个主/从 pty 对,然后允许从串行设备读取的程序改为从 pty 读取,以便所有读取进程都接收数据从串行设备开始,让 pty 像串行设备一样工作,因为当它们开始从 pty 读取时,它们只会获得最新的数据。换句话说,您不会得到任何在开始阅读之前写入的数据(根据我的经验,这就是 /dev/ttyXX 设备的工作方式,或者至少是我正在阅读的 RS-232 风速计)。命名管道可以通过捕获 SIGPIPE 来模拟这些语义,以确定没有读取器,因此我们可以选择不写入特定的命名管道。然而,一些为使用终端而编写的二进制文件在与命名管道通信时可能会失败,因为检查 isatty() 和 tcsetattr() 等调用时的 errno 条件可能会导致失败条件。这里的关键是能够使用为终端编写的现有二进制文件。

因此,如果我可以检测到 pty 的从属端何时打开进行读取,这应该给我提供与命名管道案例中没有 SIGPIPE 大致相同的语义。我注意到 HP-UX 有 TIOCTRAP 作为 ioctl() 命令,这似乎完全符合我的要求,但遗憾的是它在 Linux 上不可用。

我已经阅读参考资料好几天了,这类事情的选项数量惊人。答案可能在于终端设置、阻塞/非阻塞行为、在某处设置缓冲区大小、从 poll()/select() 报告的条件或某种组合。不过,我似乎找不到任何东西。我想知道是否有可能我需要编写自己的设备驱动程序,但似乎我应该能够做到这一点而无需走那么远。

所以,为了澄清:
- 问题是:如何检测有人在 Linux 中打开 pty(伪终端)的从属端?
- 我希望阅读器打开 pty 的从端以在阅读器打开 pty 后严格接收写入的数据(如果我的多写过程只是在阅读器打开从端之前写入数据一段时间,数据将缓冲起来并最终写入器将阻塞,从属读取器在打开时将立即获取所有缓冲数据——这是不可取的,因为我希望它只获取在紧邻时间附近生成的数据)
- 它必须是一个 pty,而不是命名管道、套接字等,因为 isatty() 和 tcsetattr() 等需要正常,这样现有的二进制文件才能工作

【问题讨论】:

    标签: linux file file-descriptor pty


    【解决方案1】:

    你找不到这个的原因是因为没有专门的文档接口来允许它。但是,有一个技巧可以让你做到这一点。打开伪终端master(这里假设为文件描述符ptm)后,打开并立即关闭slave端:

    close(open(ptsname(ptm), O_RDWR | O_NOCTTY));
    

    这会在 tty 主机上设置 HUP 标志。现在,您可以使用 poll() 定期轮询 HUP 标志(例如,每当数据来自您的数据源时):

    struct pollfd pfd = { .fd = ptm, .events = POLLHUP };
    poll(&pfd, 1, 10 /* or other small timeout */);
    
    if (!(pfd.revents & POLLHUP))
    {
        /* There is now a reader on the slave side */
    }
    

    如果读者离开,POLLHUP 将被重新设置。

    在您的情况下,您可能甚至不需要从一个循环到下一个循环记住给定的 pty 是否有阅读器 - 只需在您的数据源上阻止 read(),然后当数据可用时,同时 @987654327 @你所有的主tty,并将数据发送给没有设置POLLHUP的任何一个。

    【讨论】:

    • 感谢您的解释。我在源代码中发现了这个技巧来“socat”,但没有意识到我必须打开然后关闭从属端。即使在理解了这个技巧之后,我仍然有一些令人毛骨悚然的情节,因为我使用的是 openpty() 而不是显式打开 /dev/ptmx 这给了我一个单独的、为 pts 开放的 fd,因此我无法获得 HUP 条件原来。调用 openpty() 然后关闭从它返回的从 fd 就足够了。再次感谢您的回复。您是如何了解未记录的功能的?
    • 我想我是通过在 usenet 上发帖找到的。不过,这个问题应该会让人们在未来更容易被谷歌搜索!
    【解决方案2】:

    在从属 pty 上添加一个 inotify 监视并对其进行轮询。您可以在打开时获得 inotify 事件。然后,您可以轮询 inotify 文件描述符和主 pty 文件描述符。您可以获得打开的 inotify 事件 (IN_OPEN)。这将在从端打开时解除对轮询的阻塞。

    【讨论】:

      猜你喜欢
      • 2021-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-07
      • 2015-01-08
      • 2015-04-19
      相关资源
      最近更新 更多