打开伪终端意味着打开了一个“终端对”,这个终端对的其中一个是主终端,另一个是从终端,简单说主终端和类似sshd,telnetd等用户空间的远程协议处理进程连接,而从终端则和shell之类的实际进程连接,在处理远程登录的时候,一般都是由远程协议处理进程打开主终端和从终端,然后就在远程网络终端和本机shell之间建立了一条双向通道--“远程网络终端-(套接字)--本机协议处理进程--主终端--从终端--shell”,在这个“打开主从终端建立连接”的语义以及其实现上,有着不同的标准,总的来说有三种方式,分别是SVR4的方式,BSD的方式以及linux的方式,在“建立连接”的语义上SVR4的方式使用“流”来建立这条连接,而BSD和linux则是自动建立的,在“打开主从终端”的语义上,SVR4和linux是自动确定主终端并打开主终端后自动确定从终端,而BSD则必须手工确定和打开主终端,可见linux处理伪终端的方式是结合SVR4和BSD两种UNIX标准的结果,linux不仅实现这种有意义的最佳组合,而且分别实现了SRV和BSD的两种方式的接口,如果编译CONFIG_LEGACY_PTYS宏,则可以使用BSD的方式,如果编译CONFIG_UNIX98_PTYS,则实现SRV4的接口。
     参见《unix环境高级编程》的第19章,在用户空间,SVR4的方式为:
int ptym_open(char *pts_name)
{
    strcpy(pts_name, "/dev/ptmx"); //准备主终端的文件名字
    fdm = open(pts_name, O_RDWR);  //打开主终端
    grantpt(fdm);  //连接次终端
    ptr = ptsname(fdm); //得到次终端的文件名字
    strcpy(pts_name, ptr);
    return fdm;
}
int ptys_open(int fdm, char *pts_name)
{
    fds = open(pts_name, O_RDWR); //打开次终端
    ioctl(fds, I_PUSH, "ptem");   //压入一个伪终端虚拟模块
    ioctl(fds, I_PUSH, "ldterm"); //压入行规程模块
    return fds;
}
而BSD的方式却是:
int ptym_open(char *pts_name)
{
    ...
    //一个for循环,从/dev/ptyp0开始一直找到/dev/ptyTf为止,寻到第一个没有被使用的作为主终端,然后将对应的文件名的ptyXY中的p改为t,即ttyXY就是次终端
    pts_name[5] = 't';  ///dev/ptyXY中的第6个元素就是p,现在改为t
    return fdm;
}
int ptys_open(int fdm, char *pts_name)
{
    fds = open(pts_name, O_RDWR); //打开次终端
    //无需压入流模块,因为对于bsd来讲,其驱动程序是基于硬编码和clist的。
}
可见SRV4和BSD的方式根本不同,通过理解这种不同,我们也能更加明白/dev目录下的关于终端文件的命名规则了。关于流机制,BSD没有实现,可能是由于BSD自最初就没有SRV经过良好的规划吧,加之流的作者直接贡献流机制于SRV,那时unix已经分裂了。从终端的行规程以及任何终端的行规程之类其实也是一种协议,只是该协议主要规定人-机界面的规则,之所以将之称为行规程就是因为该规程在标准模式下限制了一次输入的结束就是一个换行符,这就是一个行规成协议,毕竟机器并不知道何时人们会输入完毕也就不能预先读取特定大小的数据块,而只能硬性规定一个特殊的字符作为输入结束,该特殊字符就是换行,类似tcp/ip协议,只是没有后者普遍罢了,使用压入流的方式,你可以轻易的堆积一个协议栈,只要将/dev/ip|udp|tcp等协议设备文件依次用ioctl的I_PUSH命令堆积即可。行规程压入了从终端并没有压入主终端,可见主终端仅仅起到一个数据中转的作用,主终端之所以不需要行规程,那是因为从终端可以处理直接从进程写入的数据或者说可以处理数据边界以及转义问题,这是无关紧要的,完全可以重新实现一个伪终端驱动,然后在主从终端都压入行规程模块,这样就显得更加对称了,正如linux后来实现的那样,虽然linux并没有显式地实现流机制,在linux中的伪终端tty的write函数中,主从终端都是统一一致的,如此一来在linux中,主从终端就更加像一对管道了,起码比SRV的要对称:
static int pty_write(...)
{
    struct tty_struct *to = tty->link; //直接获取“一对的另一半”
    ...
    to->ldisc.receive_buf(to, temp_buffer, NULL, n);//将数据放入另一半的缓冲区
    ...
}
如果看一下linux实现pty的源码,就会发现实际上pts使用的行规程是tty_ldisc_N_TTY,其receive_buf对数据其实并没有做太复杂的加工,因此这条管道并不复杂。
     在打开一对终端方面,linux实现了两种方式,SRV4的方式和BSD的方式,总之,实现这两种接口是之前unix标准混战的结果。以SRV4的方式为例,linux中使用了一个/dev/ptmx设备文件,该设备文件只有一个却可以集中代表所有的主终端,任何sshd,telnetd之类的进程都可以只使用者一个终端设备文件,虽然设备文件是一个,但是由于内核中file数据结构是基于进程的,因此各个进程对该设备文件的引用却可以容纳不同的数据,包括不同的从终端。在ptmx_open中,不仅系统可以自动分配一个主终端,而且还为该主终端绑定了一个从终端,主终端设置到file结构体的private_data字段上,之后诸如sshd,telnetd之类的进程读写/dev/ptmx文件时,虽然它们读写的是同一个文件,可是由于file结构体不再它们之间共享,因此它们取到的file->private_data也就不同了:
static int ptmx_open(struct inode * inode, struct file * filp)
{
    struct tty_struct *tty;
    int index;
    idr_pre_get(&allocated_ptys, GFP_KERNEL); //和BSD的实现不同,SRV的方式在内核中查找可用的主终端
    idr_ret = idr_get_new(&allocated_ptys, NULL, &index); //得到新的项
    ...
    retval = init_dev(ptm_driver, index, &tty);//此中实现终端对的相互link
    filp->private_data = tty; //重要的赋值
    devpts_pty_new(tty->link); //linux中的从终端设备文件是动态生成和删除的,因此linux使用了其强大的VFS机制,通过实现一个pts文件系统来支持这种动态的增删。
    ...
}
SRV4使用伪终端的方式是一对多的,ptmx集合了所有的主终端,同一个文件在不同的进程空间做区分,而BSD的方式却直接将多个一对一的终端对开放给接口调用者。在init_dev中,最为重要的一段是:
tty = alloc_tty_struct(); //分配主终端
initialize_tty_struct(tty); //初始化主终端的线路规程之类,包括些许工作队列
tty->driver = driver; //指定driver
tty->index = idx;
...
o_tty = alloc_tty_struct(); //分配从终端
initialize_tty_struct(o_tty); //初始化主终端的线路规程之类
o_tty->driver = driver->other; //pty_init的时候,主从driver都将other设置为对方
o_tty->index = idx;
tty_line_name(driver->other, idx, o_tty->name);
...
tty->link   = o_tty; //连接彼此,从此以后两个终端一主一从构成一个包含很多控制功能的管道
o_tty->link = tty;
linux的sshd等进程在调用完/dev/ptmx的open之后,实际上一对终端就建立起来了,由于没有实现SRV4的流机制,因此不需要在用ioctl将更多的协议模块PUSH上去了,这个过程直接在init_dev中就做了,可以猜想一切基于SRV4标准实现的OS,其ptmx的open要简单的多,因此init_dev简单得多,不需要系统做任何事,后续的所有工作几乎全靠调用者来用ioctl完成,比linux更灵活,但是对于很多凡人来讲也更繁琐。

十分欣赏SRV的那种I_PUSH实现的将ip,icmp,udp等堆积成协议栈的方式--流机制,同时更乐于使用linux这种将一切都做好,但是还可以定制的OS。

本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1271801

SVR4/4.3BSD与Linux对待伪终端的不同方式相关推荐

  1. linux下伪终端的使用,Linux运维培训 Linux伪终端详解

    原标题:Linux运维培训 Linux伪终端详解 Linux运维培训 Linux伪终端详解Linux学习绕不开一个名词"终端",对于新手来说可能不了解,对于老鸟来说,可能弄不大清楚 ...

  2. linux 伪终端 pty 简介

    伪终端 伪终端(pseudo terminal,有时也被称为 pty)是指伪终端 master 和伪终端 slave 这一对字符设备.其中的 slave 对应 /dev/pts/ 目录下的一个文件,而 ...

  3. 模拟linux终端测试java,Linux 伪终端(pty)

    通过<Linux 终端(TTY)>一文我们了解到:我们常说的终端分为终端 tty1-6 和伪终端.使用 tty1-6 的情况一般为 Linux 系统直接连了键盘和显示器,或者是使用了 vS ...

  4. android 伪终端,伪终端(pty)机制祥解

    -----------------------------------------------------------本文系本站原创,欢迎转载! 转载请注明出处:http://sjj0412.cubl ...

  5. linux的终端,网络虚拟终端,伪终端

    linux的终端,网络虚拟终端,伪终端 转自:http://www.xuebuyuan.com/877887.html Linux上许多网络服务应用,如l2tp.pptp.telnet,都用到了伪终端 ...

  6. Linux伪终端怎么退出,什么是linux里的终端和伪终端

    1).首先明确: 控制终端(/dev/tty) 这是个在应用程序中的一个概念,前台进程有个控制终端,就对应这个.不过它并不指任何物理意义上的终端,其实/dev/tty会映射到当前的设备(通过tty命令 ...

  7. linux 伪终端原理,探索Linux之 终端模拟器和伪终端交互原理

    写在前面:本人水平有限,不少地方都是本身的理解,若有误导,欢迎指正linux # 终端模拟器指的是在linux桌面环境下运行的仿真终端(以下图)shell # 终端模拟器为啥叫模拟器呢? 由于真正的终 ...

  8. 探索Linux之 终端模拟器和伪终端交互原理

    写在前面:本人水平有限,很多地方都是自己的理解,如有误导,欢迎指正 # 终端模拟器指的是在linux桌面环境下运行的仿真终端(如下图) # 终端模拟器为啥叫模拟器呢? 因为真正的终端是全屏显示的黑乎乎 ...

  9. linux的tty , pts 和notty pty伪终端

    当你在本地登录 Linux 机器时,登录终端会在进程列表中显示为 tty( 比如,tty7).若你通过 ssh 登录一台远程服务器,则会看到类似 root@pts/0 这样的东西. 而若某个连接是由 ...

最新文章

  1. Java知识点总结(JavaIO-合并流类)
  2. ORACLE的基本语法集锦
  3. OpenCV C++ 01 - Load Image from File and Display
  4. jzoj3461-小麦亩产一千八【斐波那契数列】
  5. Java BigDecimal stripTrailingZeros()方法与示例
  6. 近100个Spring/SpringBoot常用注解汇总!
  7. vue 父组件获取接口值传到子组件_vue父组件异步获取数据传给子组件的方法
  8. 快克SEO站群搜狗提交工具
  9. redis专题:redis键值设计、性能优化以及redis连接池配置
  10. python set集合转numpy.array
  11. 徐思 201771010132
  12. 计算机cmd测试,电脑cmd命令怎么测试网速详细步骤
  13. 昭阳 E43A 的笔记本电脑 开启或者关闭笔记本自带无线网卡
  14. Kindle 通过邮箱发送电子书
  15. linux镜像文件32,centos7光盘镜像下载32/64位
  16. (3)JavaScript基本概念
  17. 这100个shell脚本案例,你都知道吗?一篇教会你写90%的shell脚本
  18. 奥的斯电梯服务器自动呼梯,eCall BLE
  19. 电子科大复试计算机程序设计c语言,2019电子科技大学计算机软件考研复试手册.docx...
  20. 【软件推荐】第5节:奶牛快传

热门文章

  1. JavaSE学习52:细说多线程之Thread类和Runable接口
  2. 为什么深度学习几乎成了计算机视觉研究的标配?
  3. iOS容易造成循环引用的三种场景,就在你我身边!
  4. java设计模式0--设计模式简介
  5. Coursera课程Python for everyone:chapter6
  6. Lua 5.1 参考手册
  7. 自定义Xcode 文件头部的注释
  8. flex和box、flexbox高度自适应常见坑
  9. 注意啦!10 个你需要了解的 Linux 网络和监控命令
  10. Sublime Text Package Control错误另解