用户可以使用 3270 终端模拟器访问 z/OS® 主机。在这篇文章中,将学习如何构建简单的 UNIX® 或 Linux® shell 脚本,利用该脚本通过第二个终端模拟器实时查看主机用户的一举一动。
用户通常通过 3270 终端模拟器 —— 例如 IBM Personal Communications(PCOMM 是一个主机通信和终端模拟包,提供了 3270、5250 和 VT 模拟功能,提供 SNA 应用程序支持、集成,以及 SNA 和 TCP/IP 连接)—— 连接主机(System z™)。如果这些用户与支持团队在一个地点,那么支持人员就能容易地帮助他们解决问题。
但是,现在的用户通常分布在不同的地方。有的是在家里工作的员工,有的是参加在线培训课程(instructor-led online,ILO)的学员,所以想通过查看用户的屏幕来帮助他们解决问题通常是不现实的。
在这篇文章中,将学习如何构建一个在 UNIX 或 Linux 上运行的简单 shell 脚本,由这个脚本可以进入 3270 终端模拟器的用户会话(3270 终端模拟器会话是访问 z/OS 主机会话的入口)。通过该脚本,能够运行第二个终端模拟器,用这个模拟器可以实时地看到用户的一举一动。
首先来看看终端模拟的工作方式。
终端模拟会话的工作方式
终端模拟器通常用 TCP/IP 连接主机。根据 IP 地址和端口号来区分会话,IP 地址指定了参与会话的计算机,端口号则表示计算机上的程序。主机上用来侦听终端模拟器的 telnet 端口是端口 23。
图1.端口和 IP 地址
图 1 显示了两台连接到主机的 PC。主机使用 IP 地址 9.1.2.3 和端口 23。第一台 PC 有两个 PCOMM 实例 — 一个运行在端口 5000 上,另一个运行在端口 5025 上。第二台 PC 上运行了一个实例,运行在端口 5000 上。因为每个通信都包含源 IP 地址和源端口,所以主机能够区分这三个不同的连接。
选择的操作系统:Knoppix
如果没有使用 UNIX 或 Linux 系统,我建议使用 Knoppix。这个 Linux 版本可以直接从光盘上运行,所以可以在任何 PC 上运行它,甚至不需要使用 PC 的硬盘。在只有 256MB 内存的老 PC 上也能运行。
在 Knoppix 启动后,单击启动命令行窗口的图标,如图 2 所示:
图 2. Knoppix 命令行图标
要成为系统管理员,请运行 sudo bash 命令。每次打开新的命令行窗口时都要重新运行它。
多数网络都使用 DHCP 协议自动分配 IP 地址。要检查是否拥有 IP 地址,请运行以下命令: ipconfig eth0。如果没有 IP 地址,就会被分配一个地址以及路由器的地址。要启动网络功能,请运行以下命令:
ipconfig eth0 <computer's IP address> route add default gw <router's IP address> |
要检验到主机的连接,请运行以下命令: telnet <mainframe's IP address>。如果能够工作,可以使用 Ctrl-] 退出终端或启动另一个命令行窗口。如果有必要,可以运行 sudo bash。
监视单个用户的连接
这一节介绍:
- 如何设置使用管道的单一代理
- 命令在设置期间做了什么
- 如何添加监视 tap
使用管道的单一代理
第一步是创建一个代理。我们并不直接连接主机,而是让用户连接到运行 Knoppix 或其他版本 Linux 的 PC,然后让这台计算机连接到主机(如图 3 所示):
图3. 用户通过代理连接
以 root 用户身份运行以下命令:
mknod pc2mf p mknod mf2pc p cat pc2mf | nc <mainframe IP> 23 | tee tap | tee mf2pc & cat mf2pc | nc -l -p 2300 | tee mf2pc & |
现在用 3270 终端模拟器在 2300 端口上连接到运行 Linux 的计算机 — 应该被重定向到主机。连接完成之后,应该停止第三行、第四行执行的所有命令。除非后台运行其他命令,否则可以使用下面的命令执行:
kill %1 kill %2 |
工作方式
前两行命令创造一对先进先出(FIFO)管道。
mknod pc2mf p #For the stream going from PC to mainframe mknod mf2pc p #For the stream going from mainframe to PC |
第三行:
cat pc2mf | nc <mainframe IP> 23 | tee tap | tee mf2pc & |
复杂一些。它包含四个命令,这四个命令通过管道连接在一起。这意味着第一个命令的输出是第二个命令的输入;第二个命令的输出是第三个命令的输入;第三个命令的输出是第四个命令的输入。这有点像在 JCL 作业中使用 PASS 关键字将一个作业步骤的输出传递给另一个作业作为输入:
- cat pc2mf 从管道读入从 PC 到主机的数据流。
- nc <ip address> 23 打开到主机的 TCP 连接,并将管道的输出发送到该连接。
- 主机的输出然后进入下一部分,tee tap。tee 命令的功能是作为 T 管道,将输入(主机的输出)发送到下一条命令和称为 tap 的文件。后面在监视的时候将使用这个文件。
- tee mf2pc 将主机的输出发送到 mf2pc 管道。它的末尾有一个 & 符号,告诉计算机在用户执行其他操作的时候,在后台运行该命令。
第四行与第三行类似:
cat mf2pc | nc -l -p 2300 | tee mf2pc & |
- cat mf2pc 命令读取从主机到终端模拟器的流。
- nc -l -p 2300 命令侦听 TCP 端口 2300。如果程序(例如终端模拟器)连接到该端口,就会通过该连接得到来自主机的流。发送到该连接的任何内容都会转到下一个程序……
- tee pc2mf 则将内容放到第三行命令要检索的管道内。
图 4 演示了这个过程。
图 4. 简单代理
添加监视 tap
来自主机的输出还要发送到称为 tap 的文件内。因为流的格式是 EBCDIC 而非 ASCII,所以在 Linux 上没有方便的方法可以查看它。但是,在停止代理之后,可以运行下面这些命令重新启动一个可以从另一个 3270 终端模拟器访问的 tap:
rm -f tap mknod tap p cat pc2mf | nc <mainframe IP> 23 | tee tap | tee mf2pc & cat mf2pc | nc -l -p 2300 | tee mf2pc & cat tap | nc -l -p 2301 & |
前两行删除现有的 tap 文件,并用另一个 FIFO 管道代替它。第三和第四行运行简单代理,就像前面的代码示例中做的那样。最后一行读取来自 tap 的信息,并将信息发送到 nc -l -p 2301,它将侦听 TCP 端口 2301。如果程序(例如终端模拟器)连接到端口 2301,就会通过连接得到主机截取的流。但是,它发送回来的内容会被发送到执行该命令的命令提示符。图 5 演示了安装了该 tap 的代理。
图 5. 带有监视 tap 的简单代理
使用同一个 TCP 端口的多个连接
前面的解决方案能够工作,但是它要求每个用户连接到不同的端口,还需要手动分配端口。更好的解决方案应该能用一个 TCP 端口服务多个用户。清单 1 的解决方案使用了称为 proxy.sh 的 shell 脚本:
清单 1. Shell 脚本 proxy.sh 支持一个端口上的多个连接
#! /bin/sh # Run another nc to listen for the next connection nc -l -p 2300 -c ./proxy.sh & # Create a pipe for the tap tap=/tmp/proxy.sh.$ mknod $tap p # Start the tap connection cat $tap | nc -l -p $ & echo Connection from `date` tapped at port $ >> taplist # Because this script is executed by nc, the input and output # are already the TCP connection to the user. Use nc to connect # to the mainframe nc <mainframe's IP address> 23 | tee $tap |
用 chmod +x proxy.sh 将脚本设为可执行,并用 nc -l -p 2300 -c ./proxy.sh 执行脚本。每次用户连接代理上的端口 2300 时,用户都会连接到主机,并打开一个新端口来监视用户。
为了得到端口的值,要查询文件 taplist。该文件中将包含连接和端口的日期和时间。如果您希望监视的连接之后再没有生成用户连接,那么该连接就是文件的最后一行。
第一行
第一行 #! /bin/sh 告诉操作系统,本文件是脚本文件,需要用 /bin/sh 程序(也称为 shell)解释。其他以 # 字符开始的行是注释,执行时将被忽略。
侦听连接
在使用命令行参数 -l -p <port> -c <command> 执行 nc 时,nc 将一直等待,直到在该端口上接收到连接,然后执行指定的命令。来自 TCP 连接的流是命令的标准输入,命令的标准输出通过 TCP 连接发送回去。
因为 nc 在接收到连接并执行 proxy.sh 时会停止侦听端口,所以脚本做的第一件事是启动另一个 nc 实例继续作同样的事: nc -l -p 2300 -c ./proxy.sh &。& 表示这个命令将在后台执行,在完成之前不会停止脚本。
创建 tap
因为可能同时运行这个脚本的多个实例,所以需要为每个实例创建独立的 FIFO 管道。为了区分不同的管道,脚本使用了 $$,它指的是当前的进程 ID(也称为 pid)。同时运行的对同一个脚本的多个调用将使用不同的进程 ID。
# Create a pipe for the tap tap=/tmp/proxy.sh.$ mknod $tap p |
第一行是个注释。第二行将变量 tap 的值设为 /tmp/proxy.sh.<pid>。实际上是管道的文件名。
在第三行,$tap 由前一行生成的变量的值代替。这与启动作业的用户在 JCL 作业中使用 &SYSUID 类似。
tap 连接
下一步是创建用来监视用户的 tap 连接。
# Start the tap connection cat $tap | nc -l -p $ & echo Connection from `date` tapped at port $ >> taplist |
第一行还是注释。第二行与前面创建的单连接代理中的 tap 类似,不过有两个区别:
- 管道的名称是 $tap。
- 用来监视用户的端口号不能是常数,因为脚本会同时在多个实例中运行。一次只有一个进程能侦听特定端口。所以监视用户需要连接到与 proxy.sh 实例的 pid 相同的端口号。
这个解决方案带来一个新问题。监视器如何知道要连接的端口号?第三行就是用来解决这一问题的。echo 命令接受从命令行得到的参数,并将参数写进输出。>> taplist 部分将命令的输出附加到文件 taplist 末尾。
多数消息都是这样写入 taplist 的,但有两个部分将进行解释:`date` 和 $$。如果 shell 脚本的某一部分用单引号(也称为重单符)括起来,那么将执行这个部分并将结果放在该命令行内。在上面的代码中,`date` 执行 date 命令,报告当前日期和时间,然后将得到的日期和时间放在消息内。$$ 的功能同往常一样:pid,也作为监视用户的端口号。
主机连接
脚本的最后一部分连接到主机。因为脚本的输入和输出已经连接到用户的终端模拟器,所以这一部分就非常简单。
# Because this script is executed by nc, the input and output # are already the TCP connection to the user. Use nc to connect # to the mainframe nc <mainframe's IP address> 23 | tee $tap |
在在线培训课程中使用代理
要在在线培训课程上使用这个系统,请在网络上配置一个 Knoppix 代理,然后让学员连接到代理。教师随后可以根据需要打开任意多个终端模拟器实例以监视学员的活动,并最小化它们。
如果学员练习时发现问题,教师可以通过查看相应的终端模拟器了解学员的操作。每次学员按回车时,他的终端模拟器输出就会与教师的模拟器同步。如果教师不知道哪个终端模拟器窗口与该学员对应,可以要求学员输入特定形式的关键字,然后查看哪个窗口显示了该关键字。
图 6. 带有监视 tap 的代理
(责任编辑:A6)