📄 18.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<title>C:\WINDOWS\Desktop\UnixProg\7.htm</title>
</head>
<body>
<font SIZE="2">
<h1 align="center">第十八章 调制解调器拨号器 </h1>
<p>18.1 引言 </p>
<p>与调制解调器(modem)相关的程序要处理如此种类繁多的调制解调器是很困</p>
<p>难的。在大多数Unix系统中总有两个程序来处理调制解调器。第一个是远程</p>
<p>登录程 </p>
<p>序,它允许我们拨通另外的计算机、登录和使用远程系统。在系统V中这个程</p>
<p>序叫 </p>
<p>做cu,而BSD则称它为tip。它们完成类似的工作,而且都可以处理很多不同</p>
<p>类型的 </p>
<p>调制解调器。另一个使用调制解调器的程序是uucico,它是UUCP包的一部</p>
<p>分。问题 </p>
<p>是不同种类调制解调器的具体特性一般都包含在这些程序的内部,于是如果想</p>
<p>写其 </p>
<p>他使用调制解调器的程序,我们就不得不做这些程序类似的工作。同样,如果</p>
<p>我们 </p>
<p>想要改变这些程序,使其不通过调制解调器,而利用其它介质通信(例如网络</p>
<p>连接 </p>
<p>),那么也要做很大的改动。 </p>
<p>在这一章中,我们开发了一个程序来处理调制解调器所有需要处理的细节。我</p>
<p>们把所有这些的细节都集中到这一个程序中,而不是分散在多个程序里。(这</p>
<p>个程 </p>
<p>序的构思来自于Presotto 和Ritchie [1990]所描述的连接服务器)。为了</p>
<p>使用这 </p>
<p>一个程序,我们必须能如15.3节所说明的那样调用它,并使它传回文件描述</p>
<p>符。然 </p>
<p>后,我们用这个程序来开发远程登录程序(类似cu和tip )。 </p>
<p>18.2 历史 </p>
<p>cu(1) 命令(意思是call unix)是在Version 7中出现的。但它只能处理</p>
<p>一种 </p>
<p>特殊的自动拨号单元(ACU)。伯克利的Bill Shannon修改了cu,并把它实</p>
<p>现在4. </p>
<p>2BSD的tip(1)中。这之间的最大改变是使用了一个文本文件/etc/remote来</p>
<p>存放所 </p>
<p>有的系统信息(电话号码、优先的拨号器、波特率、奇偶校验、流控制等)。</p>
<p>这个 </p>
<p>版本的tip支持六种不同的拨号单元和调制解调器,但要支持其他种类的调制</p>
<p>解调 </p>
<p>器则要修改源码。 </p>
<p>与cu和tip一样,UUCP系统也可以使用调制解调器和自动拨号单元。UUCP对</p>
<p>不 </p>
<p>同的调制解调器进行加锁,因此多个UUCP的实例可以同时运行。这样,tip和</p>
<p>cu程 </p>
<p>序就不得不遵循UUCP协议,避免与UUCP冲突。在BSD系统中,UUCP使用了它</p>
<p>自己的 </p>
<p>拨号函数。这些函数被连接到UUCP的可执行程序中,这样增加新的调制解调</p>
<p>器也需 </p>
<p>要修改源码。 </p>
<p>SVR2提供了一个dial(3)函数来将调制解调器拨号的一致特性归纳到一个库</p>
<p>函 </p>
<p>数中。这个函数由cu使用,但UUCP不使用。这是一个标准的C库函数,所以可</p>
<p>以被 </p>
<p>一般程序使用。 </p>
<p>Honey DanBer UUCP系统,是将调制解调器命令从C源程序中抽取出来,将</p>
<p>它们 </p>
<p>放在一个Dialers文件中。这就允许不修改源码就加入新类型的调制解调器。</p>
<p>但是 </p>
<p>cu和uucp所使用的访问Dialers文件的函数不是很通用。这说明cu和UUCP可</p>
<p>以不重 </p>
<p>新开发代码去处理Dialers文件中的拨号信息,但除了cu和UUCP以外的程序</p>
<p>并不能 </p>
<p>使用这个文件。 </p>
<p>在所有的这些版本的cu、tip和UUCP中,加锁保证了在同一时间只有一个程</p>
<p>序使用 </p>
<p>某一设备。因为这些程序工作在不同系统中,早期的版本不提供记录锁,而使</p>
<p>用一 </p>
<p>个早期形式的文件加锁。这会导致当一个程序崩溃时,该锁文件仍旧保留,所</p>
<p>以又 </p>
<p>开发特殊的技术来处理这种情况。(对特殊设备文件不能使用记录锁,所以记</p>
<p>录锁 </p>
<p>也不能完全解决问题)。 </p>
<p>18.3 程序设计 </p>
<p>我们来分析一下调制解调器拨号器(dialer)所应该具有的特性。 </p>
<p>1.它必须在不改动源码的情况下支持新增加的调制解调器类型。 </p>
<p>为了达到这个目标,我们使用了Honey DanBer的Dialers文件。我们将所有</p>
<p>使 </p>
<p>用这个文件来拨号调制解调器的代码都放到一个精灵服务进程中,这样任何程</p>
<p>序都 </p>
<p>可以使用15.5节中的客户机-服务器函数来访问它。 </p>
<p>2.一定要使用一些特定形式的锁,以保证当那些持有锁的程序在非正常结束</p>
<p>时能自动释放它的锁。以前那些专门的技术,如那些在大多数cu和UUCP版本</p>
<p>中仍然 </p>
<p>使用的技术,都不应再使用。 </p>
<p>我们用一个服务器精灵进程来处理所有设备加锁。因为在15.5节中的客户机-</p>
<p>服务器函数会在客户机终止时自动通知服务器,所以这个精灵进程能释放进程</p>
<p>所持 </p>
<p>有的任何加锁。 </p>
<p>3.新的程序一定要能够使用我们所开发的所有特性。开发一个新的处理调制</p>
<p>解调器的程序不应当什么都要自己实现,它拨任何类型的调制解调器应该就象</p>
<p>函数 </p>
<p>调用一样简单方便。为此,我们让中央服务器精灵进程处理所有与拨号有关的</p>
<p>操作 </p>
<p>,并返回一个文件描述符。 </p>
<p>4.客户机程序,例如cu和tip,不应当需要特别权限。这些程序不应当是设</p>
<p>置 </p>
<p>用户ID(set_user_ID)程序。但是我们要给予服务器精灵进程特殊权限,</p>
<p>允许客 </p>
<p>户机程序运行时无需特权。 </p>
<p>显然我们不能改动已有的cu、tip和UUCP程序,但应该让其它程序在我们工</p>
<p>作 </p>
<p>的基础上实现起来更加简单。当然,我们也一定要充分吸取已有的Unix
拨号</p>
<p>程序 </p>
<p>的优点。 </p>
<p>图18. 1描述了客户机-服务器工作模式的结构。 </p>
<p>图18. 1 客户机-服务器工作模式的示意图 </p>
<p>建立与远程系统的通信过程如下: </p>
<p>0.启动服务器端进程 </p>
<p>1. 客户端程序启动,使用cli_conn函数(15.5节)建立与服务器端程序的</p>
<p>连接。 </p>
<p>客户端程序向服务端发出一个请求,请求拨号远程系统。 </p>
<p>2. 服务端程序读取Systems、Devices和Dilaers配置文件来决定如何拨号</p>
<p>远程系 </p>
<p>统(我们在下一部分讲述这些文件)。如果正使用一个调制解调器,在对应的</p>
<p>Dia </p>
<p>lers配置文件中就包含了这个特定调制解调器的所有命令。 </p>
<p>3.
服务端程序打开该调制解调器设备并拨号该调制解调器。这需要一些时</p>
<p>间(一 </p>
<p>般15-30秒)。服务端程序处理所有对该调制解调器的加锁,以避免各用户间</p>
<p>的冲 </p>
<p>突。 </p>
<p>4.
如果拨号成功,服务端程序返回一个该调制解调器设备的文件描述符给</p>
<p>客户端 </p>
<p>。在15.3节中的函数可以发送和接受这个描述符。 </p>
<p>5.
客户端直接与远程系统通信。服务器端不再参与这个过程。客户端读写</p>
<p>上一步 </p>
<p>返回的文件描述符就可以了。 </p>
<p>客户端与服务端的通信过程(步骤1-4)是通过一个流管道进行的。当客户端</p>
<p>完成与远程系统的通信时,客户端关闭该流管道。服务端发现该管道关闭,释</p>
<p>放对 </p>
<p>调制解调器设备的加锁。 </p>
<p>18.4 数据文件 </p>
<p>在这一部分,我们描述Honey DanBer UUCP系统所使用的三个文件:</p>
<p>Systems、 </p>
<p>Devices和Dialers。在这些文件中有很多UUCP所使用的域。我们这里不详</p>
<p>细讲述 </p>
<p>这些域和UUCP系统本身。参考Redman [1989]可得到更详细的信息。 </p>
<p>18.2 分栏列出了在Systems 文件中的六个域。 </p>
<p>name time type class phone login </p>
<p>host1 </p>
<p>host1 </p>
<p>host1 </p>
<p>modem </p>
<p>laser Any </p>
<p>Any </p>
<p>Any </p>
<p>Any </p>
<p>Any ACU </p>
<p>ACU </p>
<p>ACU </p>
<p>modem </p>
<p>laser 19200 </p>
<p>9600 </p>
<p>2400 </p>
<p>19200 </p>
<p>19200 5551234 </p>
<p>5552345 </p>
<p>5556789 </p>
<p>- </p>
<p>- (not used) </p>
<p>(not used) </p>
<p>(not used) </p>
<p>(not used) </p>
<p>(not used) </p>
<p>图18.2 Systems 文件 </p>
<p>name 域是远程系统的名字。例如,我们可以使用cu host1这种形式的命</p>
<p>令。 </p>
<p>这里要注意的是,我们可以对同一远程系统建立多个项。系统按顺序尝试拨号</p>
<p>这些 </p>
<p>项。在18.2中名为modem和laser的项对应于与调制解调器和激光打印机的直</p>
<p>接连接 </p>
<p>。我们并不需要拨号来连接这些设备,但我们对它们仍需要打开合适的终端连</p>
<p>线, </p>
<p>并处理好加锁问题。 </p>
<p>Time域指定了拨号的星期和时间。这是一个UUCP的域。Type域指定了对这个</p>
<p>特 </p>
<p>定的name使用Devices文件中的哪一项。Class域是指线路速率(波特率)。</p>
<p>Phone </p>
<p>域指定那些type为ACU项的电话号码,而其他项的phone域是一个连字符。最</p>
<p>后一个 </p>
<p>域login,是一个字符串。它是在UUCP中远程登录时所使用的,我们不使用</p>
<p>这个域 </p>
<p>。 </p>
<p>type line line2 class dialer </p>
<p>ACU </p>
<p>ACU </p>
<p>ACU </p>
<p>ACU </p>
<p>modem </p>
<p>laser cua0 </p>
<p>cua0 </p>
<p>cua0 </p>
<p>cua0 </p>
<p>ttya </p>
<p>ttyb - </p>
<p>- </p>
<p>- </p>
<p>- </p>
<p>- </p>
<p>- 19200 </p>
<p>9600 </p>
<p>2400 </p>
<p>1200 </p>
<p>19200 </p>
<p>19200 tbfast </p>
<p>tb9600 </p>
<p>tb2400 </p>
<p>tb1200 </p>
<p>direct </p>
<p>direct </p>
<p>图18.3 Devices 文件 </p>
<p>Devices文件包含了调制解调器和那些直接连接的主机的信息。图18.3列出</p>
<p>了 </p>
<p>这个文件中的五个域。Type 域与Systems文件中type域对应。Class域也一</p>
<p>定要与 </p>
<p>systems文件中对应的class域一致,它通常指定了线路速率。 </p>
<p>设备的实际名称是对line字段加前缀/dev/。在这个例子中,实际设备是</p>
<p>/dev </p>
<p>/cua0,/dev/ttya和/dev/ttyb。另外一个域line2,没有被使用。 </p>
<p>最后一个域dialer,与Dialers文件中对应项一致。对于直接相连的项则为</p>
<p>di </p>
<p>rect。 </p>
<p>图18.4显示了Dialers文件的格式。这个文件包含了所有调制解调器的拨号</p>
<p>命令。 </p>
<p>dialer sub handshake </p>
<p>tb9600 =w- ""</p>
<p>\dA\pA\pA\pTQ0S2=255S12=255s50=6s58=2s68=255\r\c </p>
<p>OK\r \EATDT\T\r\c CONNECT\s9600 \r\c "" </p>
<p>tbfast =w- ""</p>
<p>\dA\pA\pA\pTQ0S2=255S12=255s50=255s58=2s68=255s110=1s111= </p>
<p>30\r\c </p>
<p>OK\r \EATDT\T\r\c CONNECT\sFAST </p>
<p>图18.4 Dialers文件 </p>
<p>这里只有两项,我们没有列出Devices中的tb1200和tb2400项。 </p>
<p>Handshake域本应该写在同一行,因为版面的限制,我们把它放在两行上。
</p>
<p>Dialer域是与Devices文件中的行相对应。Sub域则指定了在电话号码中等于</p>
<p>号 </p>
<p>和减号的替代字符。在图18.4中,这个域表明了用w代替等于号,逗号代替减</p>
<p>号。 </p>
<p>这样就允许Systems文件中的电话号码中含有等于号(意思是等待拨号音)和</p>
<p>减号 </p>
<p>(意思是暂停)。在不同的调制解调器上,这两个字符的含义不同,将它们代</p>
<p>换成 </p>
<p>何种字符,需在Dialers文件中指定。 </p>
<p>最后一个域handshake,包含了实际的拨号指令。它是一连串以空格分开的</p>
<p>字 </p>
<p>符串,称为期望-发送串。我们期望(一直读取,直到得到匹配字符串)得到</p>
<p>第一 </p>
<p>个字符串,然后发送(写入)第二个字符串。作为一个例子,让我们来查看</p>
<p>tbfas </p>
<p>t项。这个项是用于PEP(packetized ensemble protocol) 模式的</p>
<p>Telebit Trailb </p>
<p>lazer 调制解调器。 </p>
<p>1.第一个期望字符串是空,意思是"期望空"。这总是成功的。
</p>
<p>2.发送第二个字符串,这个字符串以\d开头,\d表示暂停两秒。然后发送</p>
<p>A。再暂 </p>
<p>停半秒(\p),发送另外一个A,暂停,再发送一个A,再暂停。接着,我们</p>
<p>发送余 </p>
<p>下的以T开头的字符串。这些都是设置调制解调器的命令。\r发送一个回车,</p>
<p>\c表 </p>
<p>明在发送字符串结尾不要开始新行。 </p>
<p>3.从调制解调器读取,直到得到字符串OK\r。 </p>
<p>4.下一个发送串以\E开头,这允许进行回应检查:每次我们发送给调制解调</p>
<p>器一 </p>
<p>个字符,我们就一直读取直到有回应。然后我们发送第四个字符ATDT。下一</p>
<p>个特殊 </p>
<p>字符\T,是指使用替代的电话号码。然后是一个回车符,然后是\c是指在发</p>
<p>送字符 </p>
<p>串后不要开始新行。 </p>
<p>5.最后的期望字符串是等待调制解调器返回CONNECT FAST。(\s意思是单</p>
<p>个 </p>
<p>空格) </p>
<p>当收到最后的期望字符串后,拨号就完成了。(当然,在这handshake字符</p>
<p>串 </p>
<p>中可能出现其它更多的特殊字符序列,我们就不详细说明了。) </p>
<p>现在来总结一下,我们对这三个文件的操作。 </p>
<p>1. 使用远程系统的名称,在Systems文件中找到相同name的第一项。 </p>
<p>2. 在Devices文件中找到对应的项,其type域和class域与Systems文件</p>
<p>中项的相 </p>
<p>应域匹配。 </p>
<p>3. 在Dilaler文件中找到与Devices文件dialer域对应的项。 </p>
<p>4. 拨号。 </p>
<p>这个过程如果失败,有两个原因:(1)对应于devices文件中line域的设备</p>
<p>已 </p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -