你能用 pty 做什么?

2023-12-05

阅读了各种资源,包括http://www.linusakesson.net/programming/tty/我对伪终端的结构和使用仍然很困惑和好奇 在 Linux 终端(bash 不是 tty)中,我们有三个流:

  • stdin
  • stdout
  • stderr

每个文件都有一个文件描述符。 这些文件描述符映射到流 FILE*。 例如,我们可以使用 fileno() 和 fdopen() 在它们之间进行切换。

我可以用 pty 做什么?

我通常认为 stdout、stdin 和 stderr 与进程相关联。 我认为说有一个与 pty 关联的 stdout、stdin 和 stderr 是不正确的。 因此,给定一个 pty(对于像 bash 这样的进程而不是它的 pid),您如何获取它们并将它们连接到 bash 意义上的终端?

单个文件描述符(对于 pty)如何映射到三个流? (显然不是) 它能以某种方式映射到一个进程吗?

当使用 openpty() 时,我想连接流程在主终端和从终端上,您需要为 stdin、stdout 和 stderr 设置单独的管道,并使用选择循环连接它们并在它们之间传输数据。

但是您是否可以假设 stdin 和 stdout 已连接(通过 tty)并仅设置一个 stderr 管道以避免 stdout 和 stderr 被合并?

如果我们有一个主进程和从进程,“额外”tty 实际上为我们做什么?


以下是我认为我知道并且相关的一些事情:

The 打开pty()函数返回一对文件描述符,代表伪终端的主端和从端。

每个文件描述符都指向字符设备 - 请参阅https://man7.org/linux/man-pages/man7/pty.7.html

现在 Unix 中的设备只是特殊文件,因此文件描述符是有意义的。

bash 终端有三个流,但 tty 只是一个通道(stdout 和 stderr 之间没有区别)。 虚拟终端(tty)也有一些“魔力”(例如线路规则)。

如果我要问 pty 的 FD 映射到什么文件,它将是设备文件 /dev/ptyX 或其他文件。

由 openpty() 创建的主/从通道的两端都有一个“终端”。

它实际传输什么数据?

我通常将文件描述符视为表示文件的内核结构表的索引。 显然,其中一些文件是流(FILE* 的内核版本),其中一些 很特别。

与终端 (tty) 关联的主要用户空间结构是使用 tcgetattr 从 FD 获得的 termios。 这允许您设置终端参数,但它不会识别任何流或进程 或行纪律。

对于您认为是文件的 FILE* 或 fd,有一组非常清晰且常用的 API 定义了您可以执行的操作。

我模糊地知道我可以用字符设备做什么(例如https://unix.stackexchange.com/questions/37829/how-do-character-device-or-character-special-files-work).

但是你能用 pty 做什么呢?

给定一个流,我们可以使用 isatty() 确定它是否有关联的 tty,并使用 ttyname() 识别该 tty。 所以在内部某个地方有一些东西是知道的 tty 和流是关联的。 isatty(STDERR_FILENO) 也是 true,所以它不仅仅是 stdin 和 stdout。


最初引起我兴趣的是一个程序,它应该是一个守护进程,但却创建了一个 ncurses UI。我一直在考虑如何让进程打开其 ncurses 按需 UI(在 pty 中)。屏幕程序可以让你做到这一点,但它在幕后做了什么。

描述此用例的问题是 -将终端附加到作为守护进程运行的进程(以运行 ncurses UI)


看待这个问题的另一种方式是从面向对象的角度来看。

有哪些函数以“pty”作为参数。它们有什么用? 如果我有一个 pty 对象。它会有哪些方法呢?

如果仅列出这些函数,则手册页中会缺少一些关键信息。前置条件、后置条件和不变量是什么。


文件描述符是每个进程的标识符,指的是内核内部文件描述。文件描述包括常规文件的位置,以及是否打开该文件以进行读取、写入、两者或仅用于路径操作。这些在文件中称为文件状态标志fcntl() 手册页。每个文件描述符都有自己的描述符标志(当前只有一个,close-on-exec,O_CLOEXEC/FD_CLOEXEC)。

FILE 流是标准 C 库抽象。如果我们忽略 GNU fopencookie() 扩展,则所有 C 流都只与一个文件描述符关联,并且只有一个 C 流可以与给定文件描述符关联。 (当然可以复制文件描述符,并使用 fdopen() 将 FILE 流与新的重复文件描述符关联起来。但是,C 库不知道两个单独的流现在共享底层文件位置,这在描述符引用文件时可能会导致问题。当描述符引用设备(例如终端或伪终端)并且原始描述符以兼容模式(读/写/两者)打开时,就没有问题。)

伪终端基本上是一个双向管道,中间有内核 termios 层。在伪终端中运行的典型进程具有引用相同文件描述的所有三个标准描述符:伪终端的从端。

termios 层不仅仅对从端读写的数据进行少量处理:它还会导致信号上升。每个伪终端还与一个大小(行数和列数,以字符为单位)相关联。当伪终端的主控端改变大小时,前台进程组中的每个进程(下面解释)都会收到一个SIGWINCH信号。如果主机关闭伪终端,则所有将其作为控制终端的进程都将收到 SIGHUP 信号。 (这也是为什么/如何在运行命令或程序时关闭终端窗口通常会杀死该命令或程序。)

每个进程最多可以有一个控制终端。每个终端最多可以与一个前台进程组关联(通过管理tcgetpgrp() 和 tcsetpgrp())。的概念session (getsid(), setsid()、前台进程组和后台进程组都涉及终端(或伪终端)。

当进程将所有三个标准 C FILE 流连接到终端或伪终端时,标准输入从主站接收数据(通过 termios 层),标准输出和标准错误都将数据发送到主站(通过 termios 层)。所以,标准输入、输出和错误并不直接相互连接,仅连接到同一个终端/伪终端从端。


假设您是一名 GTK+3 C 程序员,并且想要创建自己的终端窗口应用程序,例如 xterm 或 gnome-terminal。

The application would create a pseudoterminal for each window. Whenever it receives keyboard events, it would write the corresponding key sequence (1 for 1, : for :, and so on) to the master pseudoterminal descriptor. Everything it would read from the master pseudoterminal descriptor, it would render in the window. For the slave side, the application forks a child process, opens the slave side for all three standard streams, and either executes the equivalent of /bin/login -f $(id -un) with root privileges, or does the equivalent for the current user itself. Essentially, certain housekeeping is done for the user, and finally a login shell is opened for the user in their home directory.

大多数终端模拟器都支持ANSI 转义码以及 xterm 的扩展。终端信息数据库和 ncurses 应用程序依赖 TERM 环境变量设置为当前终端类型。 (xterm-256color 可能是 Linux 中最常见的,但也支持其他颜色。终端仿真器应在从属端启动进程时设置正确的 TERM 环境变量;本身没有自动检测。)

所有需要伪终端的事情都涉及类似终端的环境。它可能面向人类用户(如上面的 GUI 终端应用程序),也可能面向在终端中工作并代表用户操作的应用程序,如 nano、vim、emacs、links 或 lynx。

The way screen其工作原理是,即使用户未连接到该屏幕进程,它也会维护应用程序正在运行的伪终端。当用户想要分离(即断开连接但让进程继续运行)时,屏幕应用程序(运行进程的伪终端的主端)与人类正在使用的终端/伪终端分离,但继续运行。为了恢复,screen -r命令(以及已经运行 screen 时的键盘快捷键)将用户终端或伪终端重新连接到 screen 应用程序。

本质上,使用这样的终端多路复用器,您拥有连接到多路复用器应用程序的真实用户终端或伪终端(可以是像 xterm 或 gnome-terminal 这样的终端仿真器,甚至是像到本机的远程 SSH 连接这样的非终端进程) ,中继按键和输出当连接时到伪终端(多路复用器应用程序是其主终端),shell 或其他应用程序在该伪终端下运行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

你能用 pty 做什么? 的相关文章

  • dup2() 和 exec()

    include
  • 如何将不记名令牌发送到 ASP NET MVC 5 中的视图?

    我有一个 NET MVC and WEB API项目 我想打电话给WEB API controllers来自 javascript 但我没有找到将令牌发送到我的视图的方法 我想添加bearer token in Viewbag变量 使用以下
  • C# 测试活动的互联网连接。 Ping google.com

    C 2008 我正在使用此代码来测试互联网连接 因为我的应用程序必须登录到网络服务器 但是 如果用户互联网连接失败或电缆被拔出 我必须通知用户 Ping www google com to check if the user has a i
  • 动态选择和更新 LINQ 结果集中的列值

    我有一个场景 其中存在 LINQ 结果集 我使用了以下查询 var stockDetails from d in db BloodBanks where d bbUserName Session username ToString sele
  • 如何通知父线程所有子线程都已终止?

    我有一个控制台应用程序正在移植到 WPF 该应用程序有 3 个工作线程 在将一些输出结果打印到屏幕上之前 这些线程都连接到主线程 我的理解是 如果我尝试在 WPF 应用程序中执行相同的操作 GUI 将被阻止并且不会响应用户 那么如何通知父线
  • 将 void *user_data 转换为对象

    我该如何投射void something到标准 C 中的对象 具体来说我想投void userdata to std map
  • 比较 LINQ to SQL 中的两个日期

    我有一个数据库 其中有一个名为会议的表 会议日期使用以下格式存储在此表中 May 2nd 2011 例如 格式为5 2 2011 我的要求是获取两个日期 例如 2011 年 4 月 25 日和 2011 年 5 月 2 日 之间的会议 并编
  • NHibernate IQueryable 集合作为 root 的属性

    我有一个根对象 它有一个集合属性 例如 I have a Shelf object that has Books Now public class Shelf public ICollection
  • 我的 WPF 应用程序未触发 MainWindow_Loaded

    我目前正在关注Pluralsight C Fundamentals Part 1并在Classes and Objects视频部分指导我在 Visual Studio 中创建一个新的 WPF 应用程序并填写代码 这导致以下结果 namesp
  • boost::asio::io_service 是否保留处理程序的顺序?

    Does boost asio io service http www boost org doc libs release doc html boost asio reference io service html保证处理程序的调用顺序与
  • 多维数组和指向指针的指针

    创建多维数组时char a 10 10 根据我的书 它说你必须使用类似于char a 10 将数组传递给函数 为什么必须这样指定长度 您不是只是将双指针传递给 with 并且该双指针不是已经指向分配的内存吗 那么为什么参数不能是char a
  • 函数指针上的未知类型 F TYPE

    include
  • 试图使用加密来混淆我的项目打破了它

    我试图尝试不同的混淆选项 为了做到这一点 我首先尝试了加密货币 以下是我遵循的步骤 打开加密向导并选择一些选项 选择我的解决方案文件 完成向导后 我看到有些 Dll 被很好地混淆了 但我的项目现在无法构建 我注意到的两件事是 我的文件夹中有
  • 我如何知道用户在使用 ncurses (Linux) 的控制台中按下了 ESC 键?

    I have a problem in detecting whether I just got a plain ESC key just code 27 or whether it was another special key such
  • 执行存储过程时 ExecuteNonQuery() 返回 -1

    我正在尝试在 Visual Studio 中执行存储过程 下面给出 CREATE PROCEDURE dbo addStudent stuName varchar 50 address varchar 100 tel varchar 15
  • C++:LPWSTR 在 cout 中打印为地址

    我有一个类型变量LPTSTR 我打印到std cout with lt lt 在 ANSI 系统中 不知道它是在哪里确定的 它工作得很好 它打印了字符串 现在 在 Unicode 系统中 我得到的是十六进制地址而不是字符串 那么 为什么LP
  • 从视图模型调用方法的命令

    好吧 我倾向于避免使用命令 因为它们总是让我感到困惑 但我正在进行一个新项目 并且正在尝试正确构建它 并且在我看来没有任何代码隐藏 基本上我现在想做的就是连接一个按钮来触发一个命令 在我的视图模型上执行一些操作 但不知何故 如此简单的事情仍
  • 用于 nmap 输出的 C++ xml 解析器

    我是 nmap 的新手 我在 nmap 教程中看到 https nmap org book man output html https nmap org book man output html oX 选项可用于获取 xml 格式的 nma
  • DataGridView 捕获用户行选择

    我在处理选择时遇到问题DataGridView 我的网格视图包含一个金额列 表单上有一个文本框 应显示所选网格视图行的总数 因此 我需要在用户选择 取消选择 gridview 行时捕获事件并相应地计算 添加 减去 金额 我找到了两种方法 使
  • 如何使用 Ioc Unity 注入依赖属性

    我有以下课程 public interface IServiceA string MethodA1 public interface IServiceB string MethodB1 public class ServiceA IServ

随机推荐

  • 选择Android开发SDK位置时需要指定哪个文件夹?

    在 LiveCode 中设置移动支持首选项以开发 Android 时 哪个文件夹内安卓文件夹需要选择存档吗 每当我选择一个文件夹时 似乎都会出现一条错误消息 The chosen folder is not a valid Android
  • 无法从 Android 中的 Firebase Storage 获取下载网址[重复]

    这个问题在这里已经有答案了 无法从 Android 中的 Firebase 存储获取下载网址 我得到 com google android gms tasks zzn 而不是 url 下载链接 我的代码 storageReference g
  • 关于问号“惰性”模式的正则表达式

    我明白了 这里mark的意思是 懒惰 我的问题本质上是 0 9 2 vs 0 9 2 它们相同吗 如果是这样 我们为什么要写前一个表达式 惰性模式不是更昂贵的性能吗 如果不是 你能分辨出区别吗 什么是 懒惰 不情愿 匹配 与正则表达式匹配时
  • 回收站视图中的项目重叠

    当用户滚动时 我的回收器视图中的项目会重叠 注意底部重叠的文本 这是生成此视图的代码 ArrayList
  • 缓冲区之间的 Emacs 选项卡

    有没有一种方法可以在缓冲区之间切换而无需通过 buffer list 或者写入我想要切换到的缓冲区的名称 更具体地说 我想知道 emacs 是否可以在缓冲区之间进行制表 就像它在 notepad 中的工作方式一样 Emacs 22 1 及更
  • 使用“auto”的声明是否与使用具体类型说明符的 extern 声明匹配?

    考虑以下程序 extern int x auto x 42 int main Clang 3 5 接受它 现场演示 GCC 4 9 和 VS2013 没有 前者的现场演示 谁是对的 C 标准中规定的正确行为在哪里 令人惊讶的是 标准中对此的
  • 复杂的 Mongoose 过滤查询

    我正在构建一个允许用户使用侧边栏过滤结果的网站 他们选择的标准越多 搜索结果就应该越具体 见附图 用户可以选择与他们要查找的内容相匹配的过滤器 复选框 我为此使用 MongoDB 我的架构如下 brandName type String r
  • Raspberry pi 4 用 java 控制 GPIO

    我想用java控制我的树莓派4上的16 2液晶显示屏 问题是Pi4J 用java修改gpios的解决方案没有更新到pi4 还有其他解决方案吗 当我启动程序时出现此错误 pi raspberrypi desktop gpio sudo sta
  • 如何在 Yii 中为单个日期属性设置多个字段(D/M/Y)?

    我想将用户出生日期存入我的数据库 表中有一个字段称为dob 当我创建模型和 CRUD 时 它生成了文本字段dob一如既往 但我想创建三个输入 多年 几个月来 和日期 所以我的问题是如何在模型的表单中添加额外的输入 我正在考虑向模型类添加新属
  • iPhone可以与JMS通信吗?

    只是想知道是否有人知道如何在 iPhone 和 iPhone 之间发送 接收 XML 消息Java消息服务 Regards 有几种方法可以实现这一点 要么通过 MQ 附带的 HTTP 桥 我自己已经这样做了 要么使用新的 MQTT 支持 您
  • MKMapView持续监控航向

    我在位于我的顶部的图层中渲染一些内容MKMapView 除了旋转之外 整个事情都运转良好 当用户旋转地图时 我需要能够旋转我在自己的图层中渲染的内容 我发现的标准答案是使用 NSLog heading f self mapView came
  • mozilla 和 safari 的仪表栏样式

    I am using the following css on my meter bars but somehow the styling does not work on safari see below screenshots I am
  • 如何停止 while 循环

    这个 while 循环永远不会结束 例如 当我输入错误的密码时 它会一遍又一遍地进入 密码错误 部分 Logo inFile open UsernamePassword txt if inFile cout lt lt Unable to
  • 在http标头中设置身份验证令牌

    我一直在关注关于如何设置身份验证令牌的railscasthttp railscasts com episodes 352 securing an api view asciicast 我已经很好地设置了我的应用程序 它使用authentic
  • 获取字符串的每个组合

    我有一个组合学作业 涉及从特定的字符串组合中获取长度小于或等于 6 的每个单词 在本例中 它是 S a ab ba 教授刚刚开始列出它们 但我认为用程序来解决会更容易 唯一的问题是我无法得到一个好的算法来实际计算每个可能的选项 如果有人可以
  • Onchange 事件运行不佳

    我创建了以下 html 页面
  • 必须使用 fibo_ 实例作为第一个参数调用未绑定方法 f() (改为使用 classobj 实例)

    在 Python 中 我尝试在类中运行一个方法 但出现错误 Traceback most recent call last File C Users domenico Desktop py main py line 8 in
  • 将 sqlite3 db 关联到 iPhone 应用程序

    我正在尝试将 SQLite3 数据库文件与我们的应用程序关联起来 以便可以轻松地从电子邮件打开备份的数据库 然而 以下内容似乎不起作用 因为 邮件 仍然无法识别该文件 在 iPad 和 iPhone 4 上
  • Springfox swagger - 没有 Spring Boot jersey 和 gradle 的 api 文档

    我有一个带有 jersey 和 gradle 的 spring boot 应用程序 我正在尝试使用 springfox 自动生成 API 文档 我已按照此处的步骤操作 http springfox github io springfox d
  • 你能用 pty 做什么?

    阅读了各种资源 包括http www linusakesson net programming tty 我对伪终端的结构和使用仍然很困惑和好奇 在 Linux 终端 bash 不是 tty 中 我们有三个流 stdin stdout std