2022年的 Tcl/Tk 编程入门参考 10.通道基础
Tcl和一些语言都有"通道"概念,通道就像上网下载文件一样,在下载的过程之中,我们跟网站之间就建立了一个通道。同样的,当我们打开电脑上一个比较大的文件时,不是一次性就读取完毕的,它也是一部分一部分读取,就像网络下载一样。所以TCL语言里,文件的读写和网络的收发,都被归结为“通道”这样一个概念,部分命令是通用的。
我查了一下,TCL刚流行的那个年代,内存大概在4MB~8MB左右。当时内存还没有现在网络带宽大,所以那个时候,读取一个稍微大一点的文件,就跟现在从网上下一个文件差不多。所以TCL语言能把文件系统和网络系统,归结为一个“通道”的概念,也是有历史原因的。
管道
Tcl的通道跟Unix/Linux系统常见的"管道"不是一个概念。命令管道常用于Unix和linux操作系统,在windows里也支持。"管道"是一种机制,用于把命令的内容传递给其它命令,以便进一步做操作。
Tcl的通道中也包含对命令管道的支持,下面open命令会介绍。
open
Open命令的作用是打开一个通道,它用于文件、命令管道以及串行通信端口。串行通信端口,在Windows上就是COM端口(俗称串口),一般用COM+数字表示,比如COM1、COM2……对于COM设备,我手上没有,所以没法测试。我记得以前刷卡的设备和超市收银小票的打印机,都是串口的,现在是什么接口我就不清楚了。然后open命令的文档里,大约一半的内容都是串行通信端口相关的功能,这部分,只能说是有需要的朋友自行研究了。
Open命令可以通过存取权限参数来控制通道的读写权限,默认的情况下是只读。存取权限有两种设定方式,第一种是通过R、W、A这三个字母来进行设定。

第二种方式,是通过一些词汇来组合成列表来进行设定,也就是下面图片显示的这些,在这里词汇里,第一行的只读、只写、读写这三个词汇必须有一个。这里的非阻塞模式这个词汇,官方不建议使用。然后最下面的TTY终端文件这个标志,是用于Unix和Linux操作系统的,作用就是把终端文件这种特殊的文件当成文件来看待,而不是当成终端。

接下来通过例子看一下:
第一个例子是命令管道,这里我用了open命令打开了一个命令管道的通道。这里以 | 竖线开头,后面跟命令(可以带空格也可以省略空格),然后通过open命令打开的通道,我们就能读取命令的内容(对于部分特殊的命令,也可以通过通道发送内容)。在这个例子里,就是读取了whoami命令返回的用户名。
另:whoami命令是信息安全行业的一个经典命令,因为这个命令在服务器操作系统里几乎都有,不仅仅是linux,win2000、2003、2008这种操作系统,就连小型机的操作系统里也有这个命令。所以用这个命令,可以验证是否已经取得了执行命令的权限、以及当前用户是什么。
后面两个例子是文件的例子,分别使用了两种存取权限设置方式。
read
read命令读取通道内容,默认情况下读取全部内容。使用-nonewline参数,丢弃末尾换行。
还可以指定每次读取的字符数量,无论什么语言都会读取设定的字符数量(不是字节量)。比如,设定50个字符,英文就读取50个字母,中文就读取50个汉字。这里要提醒的是,一个汉字至少占用两个字节,所以无论是文件通道还是网络通道,这个命令每次的"吞吐量"很可能是不一样的。另外read会记录每次读完的位置(就像打字时,代表录入位置的光标一样),如果再次运行,它就会继续读取后续的内容。
我们在这个例子里面,以Windows系统自带的arp命令为例,大家可以先在命令提示符或者powershell里面,运行一下arp命令,不带参数的话,显示就是这个命令的说明。然后例子里第一次读取前20个字符,我们再次运行这条语句,它就会继续读取20个字符,也就是从21开始到40为止的字符。这样可以实现递进式的读取文件内容。这个功能除了一些特殊需求之外,主要用于处理大文件。此外要说的是,换行符和空格等特殊字符都会被算做字符,所以在设定的时候,要注意特殊字符的问题。
puts
puts命令:向通道内写入信息。之前使用puts命令时都是拿它当显示命令用,因为在不指定通道时,默认为 stdout 即标准输出通道。该命令完整用法为:
puts ?-nonewline? ?通道ID? 字符串(要写入的信息)
close
close命令,关闭通道。默认情况下,会完整的关闭通道。在用于网络通道或管道命令通道时,可以只关闭一半的通道,就是说把读取或者写入关闭,这种状态称之为“半关闭”,半关闭我在网络部分再举例子。
如果是敲语句测试的话,puts命令执行完毕之后,我们预计的是内容已经写入到文件里了,但打开文件的话,很大可能还是空白的。这是因为TCL语言有个缓冲机制(见flush命令),在执行关闭操作的时候,缓冲区内容都会写入文件,所以执行完close命令,文件里面就有内容。
flush
flush 命令:立刻处理缓冲区的内容。TCL语言缓冲机制:数据积攒到一定数量才会写入到文件中,这么做可以防止频繁读写存储系统。以下例子请在 tclsh 或 wish 中手动输入语句测试:
gets
gets 命令:每次运行都读取通道内一行的内容。读取后会记录位置,跟read命令类似,在部分情况下更人性化,以换行作为每次读取量的标准。默认返回本次读取的内容。
gets 通道ID ?变量名?
变量名参数是可选的,如果设定了变量名,则gets命令改为返回本次读取的字符数,并将读取的内容保存在变量里。
eof
eof 命令:验证通道是否还有内容,即否已经读取结束:结束,返回1;未结束,返回0