10

如何通过 ssh 或 telnet 将终端大小更改发送到命令行应用程序?

  1. 用户使用 ssh 或 telnet 连接到远程机器。

  2. 他们开始在 VIM 中编辑文档。

  3. 然后他们调整终端窗口的大小。

终端必须告诉 ssh/telnet 窗口大小已经改变。这是怎么发生的?

然后 ssh/telnet 使用它自己的特定方法将该更改发送到 sshd/telnetd。这些方法是什么?

sshd/telnetd 然后告诉应用程序终端大小已经改变。这是怎么做的。和从终端到 ssh/telnet 的方法一样吗?

4

2 回答 2

16

这是伪终端的混乱世界。

在本地,当您调整终端大小时,您的前台进程组会得到一个SIGWINCH,您可以使用它ioctl来获取新大小。但这与远程vim 进程有什么关系?

这个主题非常复杂,但要点是删除服务器(sshd)这样做:

  1. posix_openpt使用(或openpty)打开一个主psedoterminal设备
  2. 分叉一个新的孩子(通常这一定会成为一个外壳)
  3. 使用setsid()
  4. 打开成为其控制终端的终端设备(在步骤 1 中创建)
  5. 用步骤 4 中的 fd替换标准描述符(STDIN_FILENO和朋友)

此时,服务器进程写入主端的任何内容最终都会作为从端的输入,但带有终端线路规则,因此内核在编写某些组合时会做一些魔术 - 比如发送信号,您也可以发出ioctl调用具有有用的效果。


考虑这一点的最佳方法是探索openssh套件。

  • 客户端监听SIGWINCH- 查看clientloop.creceived_window_change_signal = 1在收到时设置

  • 该函数client_check_window_change检查该标志并告诉服务器

    packet_start(SSH_CMSG_WINDOW_SIZE);
    packet_put_int((u_int)ws.ws_row);
    ...
    

所以现在服务器应该收到一个指定(可能是新的)大小的数据包。

  • 服务器使用接收到的大小进行调用pty_change_window_size,这具有真正的魔力:

    struct winsize w;
    w.ws_row = row;
    ...
    (void) ioctl(ptyfd, TIOCSWINSZ, &w); /* This is it! */
    

这将设置从属设备的新窗口大小。如果新大小与旧大小不同,内核将向与该 pty 关联的前台进程组发送一个。SIGWINCH因此vim也获得了该信号并可以更新其对终端大小的想法。

于 2013-10-03T11:32:30.760 回答
1

调整终端窗口的大小会产生一个SIGWINCH信号。

另请参阅相关的glibc 文档

于 2013-10-03T10:55:45.810 回答