zoukankan      html  css  js  c++  java
  • 终端设备 tty,pty,pts 概念与文件描述符的联系

    1节 理解终端设备ttyptypts概念

    理解终端设备tty、pty、pts概念

    简要描述:

    • 终端设备默认具有输入、输出功能。
    • 现代我们最常用的接入服务器端的方式(如:ssh通过tcp/ip的方式连接服务器端,作为服务器的终端设备)为服务的接入方式。
    • 但服务器端默认的连接终端为tty模式,(是以串口设备的接入方式,如我们的键盘、显示器),服务器默认提供tty1...tty6共6个终端接口,用Ctrl+Alt+F1...F6切换。
    • 所以在ssh通过tcp/ip连接服务器端的时候,服务器系统会将该服务转换为ptmx设备形态(可以理解为硬件链路)接入服务器端。
    • 同时将该ssh服务fork的子进程转换为pts设备(可以理解为输入输出设备),再用PTY驱动将两个设备绑定起来。  

    第2节 终端设备与文件描述符fd(file description)及重定向的关系

    计算机3个组件 与文件描述 文件描述的数字表示 对应文件
    存储器 磁盘相关 3 ~ 65535 (终端设备执行)程序所打开磁盘上的文件
    输入设备 相关 0(符号:<或0<) /dev/stdin
    输出设备 相关 1(符号:>或1>) /dev/stdout
      错误报告 2(符号:2>) /dev/stderr

    简要描述:

    1. Linux中一切皆文件,所有的存在都以文件的形式展示出来,文件描述符专用于描述系统调用文件使用情况,为每个打开的文件都打上标识且占用一个文件描述符。
    2. 终端设备与文件描述符及重定向[ >,< ](注意不是追加重定向)不是单独存在,而是相辅相成。  
    3. 重定向主要的作用是数据源流从一个设备流向另一个设备中。(磁盘上的所有类型文件,在概念上都属于设备文件,因为文件都是保存在磁盘中,对文件的操作,其本质上就是对磁盘操作)。
    4. 终端设备一般含有计算机的3大部件中的输入设备和输出设备(这与计算机发展历史相关,输入设备可以是键盘或其他能输出数据的设备,输出设备可以是显示器或其他能接收数据的设备)。
    5. 每个终端设备接入Linux系统,系统为该终端的输入功能绑定为0的文件描述符,输出功能绑定为1的文件描述符,在处理终端设备发送过来的指令出现错误时,错误提示绑定为2的文件描述符。

    第3节 终端设备与文件描述符及重定向的默认行为

    3.1 终端设备与文件描述符及重定向的默认行为

      默认情况下:系统会帮用户默认补全输入及输出的重定向路径。所以一般情况下,手工写上重定向时,就是修改系统默认的输入与输出的路径。

    比如:

      cat jeson.sh   # 等效 cat 0< jeson.sh 1> /dev/pts/0

      处理方法   输入设备负责为处理的方法提供数据源    处理完的结果交给输出设备(由输出设备将数据输出)
    用户输入 cat     jeson.sh      
    系统自动补全 cat 0 < jeson.sh 1 > /dev/pts/0
       

    输入设备

    可理解cpu获取数据入口

       数据源设备  发送设备

    可理解cpu输出数据的出口

       接收设备

      磁盘上的所有类型文件,在概念上都属于设备文件,因为文件都是保存在磁盘中,对文件的操作,其本质上就是对磁盘操作。磁盘属于存储设备。 

    3.2 描述符与重定向;将数据重定向相应的设备中

    pts/0  将echo输出的数据,定位到/dev/tty1 的输出设备

    tty1  显示pts/0输入的数据

    [jeson@mage-jump-01 ~/]# who
    root     tty1         2018-10-02 17:57
    jeson    pts/0        2018-10-02 20:12 (10.0.0.1)
    [root@mage-jump-01 ~/]#ll /dev/fd/  # 查看自身的登录终端
    总用量 0
    lrwx------ 1 root root 64 10月  2 20:16 0 -> /dev/pts/0
    lrwx------ 1 root root 64 10月  2 20:16 1 -> /dev/pts/0
    lrwx------ 1 root root 64 10月  2 20:16 2 -> /dev/pts/0
    lr-x------ 1 root root 64 10月  2 20:16 3 -> /proc/19301/fd
    [root@mage-jump-01 ~/]# echo "how are you today?" >/dev/tty1
    [jeson@mage-jump-01 ~/]# who
    root     tty1         2018-10-02 17:57
    jeson    pts/0        2018-10-02 20:12 (10.0.0.1)
    [root@mage-jump-01 ~/]#ll /dev/fd/  # 查看自身的登录终端
    total 0
    lrwx------ 1 root root 64 Oct  2 20:21 0 -> /dev/tty1
    l-wx------ 1 root root 64 Oct  2 20:21 1 -> /root/test.txt
    lrwx------ 1 root root 64 Oct  2 20:21 2 -> /dev/tty1
    lr-x------ 1 root root 64 Oct  2 20:21 3 -> /proc/19376/fd
    [root@mage-jump-01 ~/]#how are you today?

     pts/0和tty1 终端登录后的PID号

    [jeson@mage-jump-01 ~/]$ps aux|egrep "[p]ts|tty"
    USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    root      18588  0.0  0.3 116624  3408 tty1     Ss+  18:06   0:01 -bash
    jeson     19491  0.0  0.2 156676  2328 ?        S    20:32   0:00 sshd: jeson@pts/0
    jeson     19492  0.0  0.3 116616  3232 pts/0    Ss   20:32   0:00 -bash
    jeson     19648  0.0  0.1 155324  1864 pts/0    R+   20:36   0:00 ps aux
    jeson     19649  0.0  0.0 112720   992 pts/0    S+   20:36   0:00 grep -E --color=auto [p]ts|tty

    只要有PID号,/proc就会为其pid建立一个目录,该目录放该pid相关的数据文件

    [jeson@mage-jump-01 ~/]$ls /proc/ | grep -E '[1-9]+' | column
    1       17      19491   221     242     27      30      492     501     665
    10      18      19492   222     243     270     342     493     502     7
    11      18024   19636   224     263     271     365     494     503     743
    1164    18588   19668   229     264     272     38      495     505     8
    1166    18891   19669   231     265     273     40      496     57      88
    13      19      19670   233     266     274     41      497     650     9
    14      19398   2       236     267     28      42      498     651
    15      19413   20      237     268     29      44      499     653
    16      19489   21      239     269     3       476     5       658

    3.3 终端设备接入系统,系统为终端设备设置对应文件描述符的操作方式(0,1,2)

    系统为每一个接入终端都配备默认的文件描述符
    [jeson@mage-jump-01 ~/]$ll /dev/std*
    lrwxrwxrwx 1 root root 15 10月  1 18:38 /dev/stderr -> /proc/self/fd/2
    lrwxrwxrwx 1 root root 15 10月  1 18:38 /dev/stdin -> /proc/self/fd/0
    lrwxrwxrwx 1 root root 15 10月  1 18:38 /dev/stdout -> /proc/self/fd/1 
    系统为pts/0接入终端默认绑定的文件描述符操作
    [jeson@mage-jump-01 ~/]$ll /proc/self/fd
    总用量 0
    lrwx------ 1 jeson jeson 64 10月  2 21:12 0 -> /dev/pts/0  # stdin与pts/0远程终端关联
    lrwx------ 1 jeson jeson 64 10月  2 21:12 1 -> /dev/pts/0  # stdout与pts/0远程终端关联
    lrwx------ 1 jeson jeson 64 10月  2 21:12 2 -> /dev/pts/0  # stderr与pts/0远程终端关联
    lr-x------ 1 jeson jeson 64 10月  2 21:12 3 -> /proc/19778/fd 
    得出系统设备、特殊文件描述符、终端的链接关系为
    /dev/stderr   ->  /proc/self/fd/2  -> /dev/pts/0
    /dev/stdin    ->  /proc/self/fd/0  -> /dev/pts/0
    /dev/stdout   ->  /proc/self/fd/1  -> /dev/pts/0 

    3.4 打开文件描述符

    1. 打开文件描述符有程序自动指定和人为手动指定编号两种方式
    2. 程序在打开文件描述符的时候,有三种可能的行为:从描述符中读、向描述符中写、可读也可写。
    3. 从lsof的FD列可以看出程序打开这个文件是为了从中读数据,还是向其中写数据,亦或是既读又写。

      例如:以下实例就是打开文件从中读、写、读写数据的(3r的r是read,w是write,u是read and write)。    

    窗口1

    窗口2 

    程序自动指定编号 人为手动指定编号
     只读模式;命令行执行如下命令 
    [jeson@mage-jump-01 ~/]$lsof -n | grep 'read.txt'|column -t
      tail  2135  jeson  3r  REG  8,2  0  41054766  /home/jeson/read.txt 
    tail -f read.txt exec 3<read.txt
    只写模式;命令行执行如下命令
    [jeson@mage-jump-01 ~/]$lsof -n | grep 'write.txt'|column -t
      cat  2099  jeson  1w或3w  REG  8,2  0  41054756  /home/jeson/write.txt  
    cat > write.txt exec 3>read.txt
    可读可写模式;命令行执行如下命令
    [jeson@mage-jump-01 ~/]$lsof -n | grep 'read_write.txt'|column -t
      vim  2197  jeson  4u  REG  8,2  12288  41054769  /home/jeson/.read_write.txt.sap
    vim read_write.txt exec 4<>read.txt

     3.5 复制、关闭文件描述符

      文件描述符的复制(duplicate),文件描述符的复制表示当前操作的文件描述符被(作用或者理解为移动)到另一个文件描述符中。

      [n]>&digit- :将文件描述符digit代表的输出文件移动到n上,并关闭digit值的描述符。

      [n]<&digit- :将文件描述符digit代表的输入文件移动到n上,并关闭digit值的描述符。

      [n]<&- :直接关闭n描述符。

    实例 1:

    [jeson@mage-jump-01 ~/]$lsof -n | grep "read.txt" | column -t
    bash    19492  jeson  3r  REG  8,2  0  41054753  /home/jeson/read.txt
    [jeson@mage-jump-01 ~/]$exec 4<&3- 
    [jeson@mage-jump-01 ~/]$lsof -n | grep "read.txt" | column -t
    bash    19492  jeson  4r  REG  8,2  0  41054753  /home/jeson/read.txt 
    [jeson@mage-jump-01 ~/]$exec 4<&-
    [jeson@mage-jump-01 ~/]$lsof -n | grep "read.txt" | column -t
    [jeson@mage-jump-01 ~/]$

    可见:fd=3移动到fd=4后,原本与fd=3关联的read.txt已经关闭,并且关联到fd=4上; 最后把fd=4直接关掉了。

    实例 2:

    [jeson@mage-jump-01 ~/]$echo "I am a boy"
    I am a boy
    [jeson@mage-jump-01 ~/]$echo "I am a boy" >/dev/null 2>&1
    [jeson@mage-jump-01 ~/]$ 

    画图说明:

    第4节 文件描述符的高阶使用 

    案例 1 :

    [jeson@mage-jump-01 ~/]$echo "123456" >jeson.sh
    [jeson@mage-jump-01 ~/]$exec 5<>jeson.sh 
    [jeson@mage-jump-01 ~/]$read -n 3 <&5
    [jeson@mage-jump-01 ~/]$echo $REPLY
        123
    [jeson@mage-jump-01 ~/]$echo -n "+" >&5
    [jeson@mage-jump-01 ~/]$exec 3>&-
    [jeson@mage-jump-01 ~/]$cat jeson.sh 
        123+56 

      简要描述:

      打开文件 jeson.sh 以read/write方式,并分配fd=5给该文件进程。
      这时fd=0已经绑定到fd=5上,而fd=5的重定向目标为jeson.sh,所以fd=0的目标也是jeson.sh,即从jeson.sh中读取数据。这里read命令读取3个字符,由于read命令中没有指定变量,因此分配给默认变量REPLY。注意,这个命令执行结束后,fd=0的重定向目标会变回/dev/stdin。
        这时fd=1也已经绑定到fd=5上,而fd=5的重定向目标文件为jeson.sh,所以fd=1的目标也是jeson.sh文件,即数据写入到jeson.sh中。这里写入一个+号。注意,这个命令结束后,fd=1的重定向目标回变回/dev/stdout。
        关闭fd=5,这也会关闭其指向的文件jeson.sh,关闭文件操作进程。

    案例 2 :

    [jeson@mage-jump-01 ~/]$exec 6>&1
    [jeson@mage-jump-01 ~/]$exec > jeson.sh
    [jeson@mage-jump-01 ~/]$echo "I am a boy"
    [jeson@mage-jump-01 ~/]$exec 1>&6-
    [jeson@mage-jump-01 ~/]$cat jeson.sh 
      I am a boy

       简要描述:

    1. 打开文件描述符进程fd=6,并指向1对应的/dev/stdout。
    2. 打开文件描述符fd=1进程指向jeson.sh文件。
    3. 输入的数据,定位到描述符fd=1进程,1进程对应jeson.sh文件。
  • 相关阅读:
    「日常训练」Single-use Stones (CFR476D2D)
    「日常训练」Greedy Arkady (CFR476D2C)
    「Haskell 学习」二 类型和函数(上)
    「学习记录」《数值分析》第二章计算实习题(Python语言)
    「日常训练」Alena And The Heater (CFR466D2D)
    Dubbo 消费者
    Dubbo 暴露服务
    Rpc
    git fail to push some refs....
    Spring Cloud (6)config 客户端配置 与GitHub通信
  • 原文地址:https://www.cnblogs.com/jeson-lbb/p/9724710.html
Copyright © 2011-2022 走看看