用Java 编 写Socket 客 户 机 端 程 序 华 中 理 工 大 学 计 算 中 心 刘 达 顷 袁 益 汉 本 文 通 过 一 个Java 程 序 介 绍 了 利 用Java 编 写 客 户 机/ 服 务 器 体 系 结 构 上 客 户 端 的socket 程 序 的 方 法。 Socket 的 概 念 Mail、ftp、telnet、name 和finger 都 是 网 络 上 的 计 算 机 提 供 的 服 务 器。( 这 些 服 务 器 均 是 软 件)。 典 型 地 讲, 每 种 服 务 器 都 是 在 一 个 专 用 的 公 开 的 端 口 上 提 供 的。 通 过 连 接 到 某 种 服 务 器 的 端 口, 客 户 程 序 就 能 够 访 问 这 种 服 务 器。 这 与 现 实 生 活 是 相 似 的 — — 当 需 要 干 洗 衣 服 的 时 候, 找 干 洗 店; 当 需 要 取 钱 的 时 候, 去 银 行, 等 等。 除 了 专 用 于 特 定 服 务 器 的 端 口 外, 计 算 机 还 有 其 它 的 端 口 让 程 序 员 创 建 他 们 自 己 的 服 务 器。 端 口 一 般 是 编 号 的, 通 过 指 定 客 户 想 得 到 的 服 务 器 的 端 口 号, 客 户 程 序 可 以 连 接 到 这 个 端 口 上。 每 种 服 务 器 或 端 口 要 有 特 定 的 协 议 — 为 了 让 客 户 的 请 求 能 够 被 理 解 和 响 应, 客 户 必 须 以 这 种 服 务 器 特 有 的 方 式 形 成 客 户 请 求。 Socket 是 网 络 上 运 行 的 两 个 程 序 间 双 向 通 信 连 接 的 一 端。Socket 这 个 词 的 一 般 意 义 是 自 然 的 或 人 工 的 插 口, 如 家 用 电 器 的 电 源 插 口 等。 客 户 程 序 可 以 向Socket 写 请 求, 服 务 器 将 处 理 此 请 求, 然 后 通 过Socket 把 结 果 返 回 给 客 户。 Socket 是 一 种 底 层 连 接。 客 户 机 和 服 务 器 通 过 写 入 到Socket 的 字 节 流 进 行 通 信。 它 们 必 须 有 共 同 的 协 议, 也 就 是 说, 通 过Socket 相 互 传 送 信 息 时 所 用 的 语 言 必 须 是 协 定 好 的。 如 果 客 户 正 试 图 连 接 到WWW, 那 么 类URL 及 相 关 类(URL Connection,URL Encoder) 比 较 适 合。 相 对 来 说,URL 是 对Web 的 高 层 连 接, 并 且 把Socket 用 作 低 层 实 现 的 一 部 分。 Java 开 发 环 境 中 的java.net 软 件 包 提 供 了Socket 类。Socket 类 实 现 客 户Java 程 序 和 网 络 上 的 另 一 程 序 间 的 双 向 连 接 的 用 户 端。 下 面 谈 谈 怎 样 使 用Socket 和ServerSocket 类。 利 用Socket 类 编 写 客 户 端Java 程 序 下 面 的 简 单 程 序 说 明 怎 样 借 助Socket 建 立 从 客 户 端 程 序 到 服 务 器 程 序 的 连 接。java.net 包 中 的Socket 类 是 客 户 端 程 序 和 服 务 器 端 程 序 间 双 向 通 信 连 接 的 客 户 端 的 实 现, 它 与 平 台 无 关。Socket 类 是 覆 盖 在 一 个 与 平 台 有 关 的 实 现 之 上 的; 它 把 具 体 的 系 统 细 节 从 客 户 的Java 程 序 中 屏 蔽 掉。 因 此, 当 使 用Socket 类 时, 应 该 使 用java.net.Socket 类, 以 便 跳 过 与 系 统 有 关 的 功 能。 通 过 这 种 方 式, 客 户 的Java 程 序 将 是 与 平 台 无 关 的。 EchoTest 这 个 客 户 程 序 通 过 一 个Socket 连 接 到 标 准 的Echo 服 务 器( 借 助 端 口8), 客 户 向 该Socket 进 行 读 写。 把 用 标 准 输 入 设 备 输 入 的 文 本 写 入 到Socket, 然 后EchoTest 向Echo 服 务 器 发 送 整 个 文 本。 服 务 器 通 过Socket 把 所 有 从 客 户 端 接 收 到 的 输 入 返 回 给 客 户。 客 户 程 序 通 过Socket 读 取 从 服 务 器 返 回 的 数 据 并 显 示 从 服 务 器 接 收 到 的 所 有 数 据。 程 序 代 码 如 下: //This is the beginning of the client_side program for socket in Java language. import java.io.*; import java.net.*; public class Echo Test{ public static void main(String [ ]args){ try{ Socket echoSocket=new Socket(“hust”,8); OutputStream os=echoSocket.getOutpustStream(); DataInputStream is=new DataInputStream(echoSocket.getInputStream)()); int c; String responesLine; While((c=System.in.read())!=-1){ os.write((byte)c); if(c==`\n'){ os.flush(); responseLine=is.readLine(); System.out.println(“echo:”+responseLine); } } os.close(); is.close(); echoSocket.close(); }catch(Exception e){ System.err.println(“Exception:”+e); } } } 程 序 分 析 try 块 内 的 前 三 行 代 码 很 关 键, 它 们 建 立 了 客 户 机 和 服 务 器 间 的Socket 连 接 并 在Socket 上 打 开 了 一 个 输 入 流 和 一 个 输 出 流。 第 一 行 创 建 了 一 个Socket 对 象 并 命 名 为echoSocket。 这 里 所 用 的 类Socket 的 构 造 方 法( 相 当 于C++ 中 的 构 造 函 数, 还 有 三 种) 要 求 指 定 客 户 想 连 接 的 机 器 的 名 称 和 端 口 号。 程 序 中 所 用 的 机 器 名hust 是 假 设 的 网 上 的 一 台 机 器, 当 在 客 户 机 上 输 入 并 运 行 本 程 序 时, 可 以 改 成 真 实 的 机 器 名。 端 口 号 为8。 块try 内 的 第 二 行 打 开Socket 上 的 一 个 输 出 流, 而 第 三 行 打 开Socket 上 的 一 个 输 入 流。 为 了 利 用Socket 与 服 务 器 通 信, 现 在EchoTest 只 需 向 输 出 流 写 数 据、 从 输 入 流 读 取 数 据。 程 序 的 其 它 语 句 就 实 现 这 个 目 的。 块try 中 的 其 它 代 码 从EchoTest 的 标 准 输 入 流( 用 户 可 以 在 此 处 输 入 数 据) 每 次 读 入 一 个 字 符。EchoTest 单 独 地 向 连 接 到Socket 的 输 出 流 写 入 每 个 字 符。 当 用 户 敲 入‘\n’ 时,EchoTest 一 次 就 把 输 出 流 全 部 送 入, 这 样 就 把 用 户 敲 入 的 一 整 行 一 次 送 入 了 服 务 器。 下 一 步,EchoTest 从 与Socket 相 连 的 输 入 流 处 读 取 一 行 信 息。 在 执 行 方 法readLine() 时, 要 等 到 服 务 器 向EchoTest 发 回 消 息 后 才 返 回, 它 返 回 时,EchoTest 向 标 准 输 出 打 印 这 条 消 息。 这 样 一 直 循 环EchoTest 从 用 户 处 读 取 输 入、 把 它 发 送 到Echo 服 务 器 再 从 服 务 器 获 得 响 应 后 显 示 响 应 信 息 一 直 至 用 户 敲 入 一 个 结 束 符。 用 户 敲 入 结 束 符 后,while 循 环 结 束 并 且 继 续 执 行 程 序 的 下 三 行。 好 的 程 序 执 行 完 的 时 候 总 要 作 一 结 束 整 理, 本 程 序 也 不 例 外。 这 三 行 代 码 关 闭 与Socket 连 接 的 输 入 输 出 流, 关 闭 与 服 务 器 的Socket 连 接。 这 里 的 代 码 顺 序 很 重 要, 必 须 在 关 闭Socket 之 前 关 闭 与 之 相 连 的 流。 程 序 中 最 后 两 行 语 句 做 到 例 外 处 理。 由 于Scho 服 务 器 实 现 的 是 一 个 简 单 的 协 议, 故 这 段 客 户 程 序 是 很 直 观 的。 客 户 机 向 服 务 器 发 送 文 本, 然 后 服 务 器 把 它 返 回 给 客 户 机。 当 客 户 程 序 与 更 复 杂 的 服 务 器( 如http 服 务 器) 通 信 时, 客 户 程 序 也 将 更 复 杂。 但 是, 基 本 的 操 作 是 相 同 的, 即:1  打 开Socket;2  打 开 与 此Socket 连 接 的 输 入 输 出 流;3  根 据 服 务 器 的 协 议 向 此Socket 写 数 据 或 从Socket 读 取 数 据;4  关 才Socket 和 流? 在Linux 下 访 问MS SQL Server 数 据 库 宁 波 保 税 区 官 委 会 计 算 中 心   董 保 华 ---- Linux 作 为 一 个 免 费 的Unix 类 操 作 系 统, 以 其 开 放 性 源 代 码、 多 任 务、X window 等 特 点 为 众 多 的 用 户 所 采 用, 并 有 很 多 企 业 采 用Linux 来 作 为 其 内 部 网 的 全 功 能 服 务 器(WWW,FTP,Email、DNS)。 企 业 的 内 部 网 不 仅 要 提 供 文 本 信 息 的 访 问, 还 要 能 提 供 对 企 业 关 系 数 据 库 中 的 信 息 的 访 问。 SQL Server 以 其 低 成 本、 性 能 高 以 及 与NT 的 有 效 集 成 等 特 性 为 许 多 企 业 所 采 用, 但Microsoft 不 提 供 其Unix 下 的 客 户 端, 为 这 类 应 用 带 来 了 困 难。 本 文 则 提 出 了 这 一 问 题 的 解 决 方 案。 安 装Sybase 客 户 端 ---- 首 先 从Microsoft SQL Server 和Sybase SQL Server 的 关 系 说 起。 两 公 司 曾 共 同 开 发OS/2 上 的 数 据 库 SQL Server for OS/2, 此 后 两 公 司 又 独 立 开 发 升 级 系 统,Sybase 的 客 户 端 可 以 访 问Microsoft SQL Server 。 ---- 和 其 他 数 据 库 公 司 相 比, 可 以 说Sybase 公 司 对Linux 是 最 有 善 意 的, 它 虽 不 提 供Linux 下 的SQL Server, 但 提 供 了 免 费 的CT -LIB 的 客 户 端, 这 也 可 能 是 许 多IT 管 理 人 员 在 为 公 司 数 据 库 选 型 时 不 再 考 虑Oracle 或Informix 的 理 由 之 一。 当 然 现 在 情 况 有 所 改 变。 ----Sybase 公 司 发 布 的OpenClient for Linux 是a.out 格 式 的, 在 互 联 网 上 有 人 将 其 转 化 为ELF 和 动 态 链 接 的ELF 格 式, 可 从 下 列 地 址 上 寻 找 下 载: http://www.mbay.net/ ~mpeppler。 最 好 同 时 下 载 两 个 版 本, 正 常 使 用 时 采 用 动 态 链 接 的 版 本, 但 有 的 程 序 在 编 译 时 可 能 需 要 一 个 库(libblk.a), 只 在ELF 里 面 包 含。 ---- 下 载 以 后, 键 入 如 下 命 令 展 开( 假 设 当 前 目 录 是/usr/tmp): ----tar zxvf linux elf dynamic tar.gz ---- 然 后 将 其 移 至/usr/local 目 录: ----mv sybase /usr/local ---- 编 译 和 使 用Sybase 客 户 端 需 要 进 行 如 下 的 设 置: ----1 . Interface 文 件 举 例 如 下: ----MSSQL ----query tcp ether mysql 1433 ---- 其 中: MSSQL 是 客 户 端 使 用 的 服 务 器 名, 以 后 引 用 MSSQL 即 可; mysql 是 服 务 器 的 地 址 或 名 字, 如 果 是 名 字, 则 系 统 能 够 查 到 其IP 地 址; 1433 是SQL Server 的 端 口 号,Microsoft SQL Server 的 缺 省 值 是1433,Sybase 是5000。 ----2 . SYBASE 环 境 变 量, 内 容 是Sybase 客 户 端 所 在 的 目 录: ----Export SYBASE=/usr/local/sybase ----3 . 如 果 编 译Sybase 客 户 端 中 的 例 子, 则 还 要 设 置 环 境 变 量SYBPLATFORM: ----export SYBPLATFORM=Linux ---- 并 且 修 改 其 头 文 件 中 关 于 服 务 器 名 称 及 用 户 名 和 口 令 的 描 述。 使 用SQSH 界 面 访 问SQL Server ----Sybase 客 户 端 提 供 了xisql 工 具, 但 更 多 的 人 使 用 的 是SQSH,SQSH 是SQshell 的 缩 写, 是 改 进 了 的 isql, 可 从 下 列 地 址 下 载:http://www.voicenet.com/ ~gray/。 当 前 的 最 新 版 本 是1.6.0。 假 设 下 载 后 的 文 件 放 在/usr/tmp 目 录 下: ----tar zxvf sqsq 1.6.0 tar.gz ----cd sqsh 1.6.0 ----./configure ----make;make install ---- 然 后, 将 生 成 的 可 执 行 文 件sqsh 安 装 到/usr/local/bin/ 目 录 下。 ----Sqsh 的 使 用 如 下: ---- # sqsh - -Uusername - -Ppassword - -Sservername ---- 其 中username 和password 是 用 户 名 和 口 令, servername 是 在interface 文 件 中 定 义 的 服 务 器 名 如 例 子 中 的MSSQL)。 ----Sqsh 是 交 互 式 的 命 令 行 界 面, 命 令 用 输 入go 来 执 行, 命 令 如 果 较 长 可 直 接 分 成 几 行 书 写, 以 回 车 换 行 即 可。 ---- 如 下 是 一 个 例 子: ----1> use pubs ----2> go ----1> select * from authors ----2> go 采 用CT -LIB 编 写 应 用 程 序 ---- 由 于Sybase 的Linux 客 户 端 不 提 供DB -Library, 所 以 应 采 用CT -Library 来 编 写 应 用 程 序, 采 用CT -Library 编 写 应 用 程 序 可 参 考 例 子, 详 细 的 编 程 说 明 可 以 参 考Sybase 的 说 明。 利 用Sybperl 编 写 应 用 程 序 ----Sybperl 是Sybase 的Perl 扩 展, 可 利 用Perl 语 言 来 访 问SQL Server, 或 者 编 写CGI 程 序。 ----Sybperl 可 从 下 列 地 址 取 得http://www.mbay.net/ ~mpeppler。 当 前 的 最 新 版 本 是2.9.5。 ---- 取 得Sybperl 的 源 代 码 展 开 以 后, 需 要 修 改 一 下CONFIG 文 件, 以 下 是 几 个 参 数: ---- 下 一 个 要 修 改 的 文 件 是PWD, 这 是 用 来 进 行 测 试 的, 将 其 中 的 服 务 器 名、 用 户 名、 用 户 口 令 设 置 成 自 己 的 配 置 即 可。 然 后 进 行 编 译: ----perl Makefile.PL ----make; make test; make install ---- 安 装 成 功 以 后, 即 可 使 用Sybperl 进 行 编 程。 下 面 是 一 个 简 单 的 例 子。     #!/usr/bin/perl    use Sybase::CTlib;     $dbh=new Sybase::CTlib 'sa','','MSSQL';     $dbh ->ct_execute("select au_id, au_lname, au_fname from pubs.dbo.authors");    while( $dbh ->ct_results( $restype) == CS_SUCCEED) {     next unless $dbh ->ct_fetchable( $restype); while(( $au_id, $au_lname, $au_fname) = $dbh ->ct_fetch){     print " $au_id - $au_lname au_fname\n";     }    } ----可 以 看 出, 短 短 几 行 语 句, 就 可 以 完 成 对 数 据 库 的 操 作。 ----以 上 从 几 个 方 面 对 在Linux 下 访 问MS SQL Server 数 据 库 进 行 了 说 明, 介 绍 了 基 本 的API 编 程、SQSH 命 令 行 访 问、Perl 访 问。 其 实, 在Linux 下 还 可 采 用 其 他 方 式 进 行 访 问, 如 采 用 第 四 级 的JDBC 进 行 访 问, 这 时 除 了Java 和JDBC 外, 并 不 需 要 其 他 软 件( 具 体 信 息 可 访 问http://www.connectsw.com)。 中国计算机世界出版服务公司版权所有 Visual C++ 5.0 编 程 经 验( 下) 北 京 大 学 计 算 机 系--蒋 志 华 实 现 操 作 过 程 提 示 对 话 框 的 一 种 方 法 ---- 在 使 用Windows95 进 行 文 件 拷 贝 或 者 删 除 操 作 时, 您 一 定 见 到 过 那 种 具 有 飞 文 件 动 画 的 操 作 过 程 提 示 对 话 框。 这 一 功 能 的 加 入 不 仅 使 我 们 能 够 在 操 作 过 程 当 中 随 时 取 消 操 作, 而 且 也 使 文 件 拷 贝 或 者 删 除 操 作 变 得 生 动 活 泼。 其 实, 在 使 用Visual C++ 进 行 应 用 程 序 设 计 时, 我 们 也 可 以 使 用 下 述 方 法 在 适 当 位 置 加 入 自 己 的 操 作 过 程 提 示 对 话 框。 为 每 一 个 操 作 过 程 提 示 对 话 框 创 建 一 个 对 话 框 类。 为 了 下 面 叙 述 方 便, 我 们 只 假 设 应 用 程 序 需 要 一 个 操 作 过 程 提 示 对 话 框 并 以“CModel” 作 为 对 应 的 对 话 框 类 的 名 字。 使 用Visual C++ 提 供 的 资 源 编 辑 器 编 辑 提 示 对 话 框, 比 如 加 入 一 些 文 字 说 明 和 动 画 等。 在CModel 类 的 头 文 件(Model.h) 中, 加 入 两 个 成 员 变 量, CWnd* m_pParent; // 指 向 调 用 该 提 示 对 话 框 的 框 架 类( 或 对 话 框 类), 即 它 的“ 父 类” int m_nID;// 记 录 该 提 示 对 话 框 的ID 号 以 及 下 面 两 个 成 员 函 数: CModel(CWnd* pParent = NULL); // 舍 弃 原 有 的 构 造 函 数, 或 者 把 原 函 数 修 改 成 这 种 无 模 式 对 话 框 的 构 造 函 数 BOOL Create(); // 该 函 数 将 调 用 创 建 基 类 的Create() 函 数 创 建 对 话 框 在Model.cpp 文 件 中, 加 入 相 应 函 数 的 实 现 部 分。 CModel::CModel(CWnd* pParent /*=NULL*/) : CDialog(CModel::IDD, pParent) { m_pParent=pParent; m_nID=CModel::IDD; //{{AFX_DATA_INIT(CModel) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } BOOL CModel::Create() { return CDialog::Create(m_nID,m_pParent); } 同 时 按 下Ctrl 和W 键 或 直 接 单 击 工 具 条 上 的ClassWizard 按 钮, 打 开ClassWizard 对 话 框。 在 类 名(Class name) 列 表 框 中 选 择 该 提 示 对 话 框 类, 在Object IDs 列 表 框 中 选 择 该 类 的 类 名 后, 在 消 息(Messages) 列 表 框 中 选 择PostNcDestroy 消 息 并 双 击 它, 这 时ClassWizard 就 会 在 该 对 话 框 类 中 加 入 一 个PostNcDestroy() 函 数。 该 函 数 将 会 在 对 话 框 窗 口 消 失 后, 由OnNcDestroy() 函 数 调 用。 因 此, 可 以 在 该 函 数 中 加 入 一 些 扫 尾 工 作, 例 如 数 据 传 送, 释 放 指 针 空 间 等。 void CModel::PostNcDestroy() { // TODO: Add your specialized code here and/or call the base class delete this; CDialog::PostNcDestroy(); } 在 要 调 用 提 示 对 话 框 类 的 类 的 头 文 件 中, 先 包 含 (#include)CModel 类 的 头 文 件, 再 声 明 一 个 指 向CModel 类 的 对 象 的 指 针, 如m_Dlg, 并 在 该 类 的 构 造 函 数 中, 加 入 “m_Dlg = NULL;” 一 句。 然 后, 在 打 开 和 关 闭 提 示 对 话 框 的 函 数 中 加 入 如 下 一 段 程 序: if (m_Dlg==NULL) {//如果当前没用提示对话框在活动,就创建一个 m_Dlg = new CModel(this); m_Dlg->Create(); GetDlgItem(IDC_EXPORT)->EnableWindow(FALSE); } else//否则就激活它 m_Dlg->SetActiveWindow(); 另外,再在要关闭提示对话框的地方,加入如下语句: m_Dlg->DestroyWindow(); m_Dlg=NULL; ---- 至 此, 您 已 经 拥 有 了 自 己 的 过 程 操 作 提 示 对 话 框。 不 过, 它 还 不 具 有 动 画 和 随 时 取 消 操 作 的 功 能。 您 不 妨 尝 试 着 加 入 这 些 功 能。 另 外, 笔 者 也 曾 尝 试 过 用 下 面 介 绍 的 方 法 实 现 过 程 操 作 提 示 对 话 框。 两 种 方 法 比 较, 可 谓 各 有 千 秋。 如 果 您 希 望 上 面 设 计 的 过 程 提 示 对 话 框 能 够 被 多 个 应 用 程 序 共 享, 那 么 最 好 把 提 示 对 话 框 作 为 独 立 的 进 程 来 调 用。 但 是, 当 您 还 希 望 在 提 示 对 话 框 与 调 用 者 之 间 传 输 数 据 的 话, 似 乎 这 一 部 分 介 绍 的 实 现 方 法 更 简 洁 且 更 有 效。 应 用 进 程 实 现 对 其 他 应 用 程 序 的 调 用 ---- 在 我 们 设 计 的 应 用 程 序 中, 很 可 能 会 用 到 其 他 应 用 程 序 来 完 成 某 一 特 定 功 能。 例 如, 当 我 们 为 了 便 于 数 据 的 传 输 而 对 诸 多 文 件 进 行 压 缩 和 解 压 缩 时, 一 种 作 法 是 我 们 自 己 设 计 一 个 这 样 的 压 缩/ 解 压 缩 程 序, 然 后 以 动 态 链 接 库(DLL) 或 者 函 数 库 的 形 式 由 主 应 用 程 序 调 用。 但 更 方 便 而 且 高 效 的 作 法 是 利 用 现 有 的 这 方 面 的 优 秀 软 件, 比 如ARJ.EXE, 并 以 进 程 的 形 式 调 用 它, 再 在 适 当 时 候 关 闭 它。 下 面 将 以 上 面 所 述 为 例, 具 体 介 绍 后 一 种 方 法 的 实 现 过 程。 在 需 要 调 用ARJ.EXE 进 行 压 缩/ 解 压 缩 的 类 中, 创 建 一 个 成 员 函 数, 不 妨 称 作CreateBat(), 其 作 用 是 生 成 一 个 批 处 理 文 件。 由 该 批 处 理 文 件 调 用ARJ.EXE, 并 给 出 具 体 压 缩/ 解 压 缩 参 数。 之 后, 再 利 用MS-DOS 的DIR 命 令 生 成 一 个 临 时 文 件, 以 作 为 压 缩/ 解 压 缩 工 作 完 成 的 标 志。 void CMyCompress:: CreateBat(CString BatPath,CString ArjPath, CString BatName,CString ArjFileName, CString TempPath,CString ExitFlag,BOOL out) { LPTSTR lpBuffer; UINT uSize; HANDLE hHeap; uSize=(GetCurrentDirectory(0,NULL))*sizeof(TCHAR); hHeap=GetProcessHeap(); lpBuffer=(LPSTR)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,uSize); GetCurrentDirectory(uSize,lpBuffer); //得知当前目录信息,以便根据需要变换目录 if (lpBuffer!=BatPath) //diferent dir SetCurrentDirectory(BatPath); CStdioFile f; CFileException e; if (!f.Open( BatName, CFile::modeCreate|CFile::modeWrite, &e)) //以BatName的内容创建一个批处理文件 { AfxMessageBox("不能创建文件"+BatName); return ; } char density[6]; sprintf(density,"%d",mTotalBytes); ---- //mTotalBytes 是 由 其 他 函 数 设 定 的 变 量, 用 于 记 录 用 于 拷 入 或 拷 出 文 件 的 磁 盘 所 具 有 的 最 大 可 用 空 间 CString Density=density; CString string; if (out)//说明是生成做压缩工作的批处理文件 string="arj a -v"+Density; else //说明是生成做解压缩工作的批处理文件 string="arj e -v"+Density; string+=" ..\\"+ArjPath+"\\"+ArjFileName+" "; if (out) string=string+"..\\"+TempPath+"\\*.* -y -jm\n"; else string=string+"..\\"+TempPath+"\\ -y -jm\n"; f.WriteString(string); string="dir >"+ExitFlag+"\n"; f.WriteString(string); f.Close(); SetCurrentDirectory(lpBuffer);//回复到原来的目录下 } ---- 该 函 数 执 行 后, 将 生 成 一 个 批 处 理 文 件, 内 容 大 致 是: ---- ARJ A -V1440 压 缩 后 文 件 的 路 径 名+ 文 件 名 被 压 缩 文 件 的 路 径 名+ 文 件 名 -Y -JM ---- DIR > 临 时 文 件 名 ---- 或 者 是: ---- ARJ E -V1440 被 解 压 缩 文 件 的 路 径 名+ 文 件 名 解 压 缩 后 文 件 的 路 径 名+ 文 件 名 -Y -JM ---- DIR > 临 时 文 件 名 在 需 要 调 用ARJ.EXE 进 行 压 缩/ 解 压 缩 的 类 中, 再 创 建 一 个 成 员 函 数, 不 妨 称 作RunBat(), 其 作 用 是 创 建 和 执 行 进 程 来 运 行 上 述 所 生 成 的 批 处 理 文 件, 并 在 适 当 时 候 撤 消 进 程。 void CMyCompress::RunBat(CString BatPath,CString fileName,CString ExitFlag) { CString lpApplicationName=BatPath+"\\"+fileName; // 进 程 执 行 的 应 用 程 序 的 完 全 路 径 名 STARTUPINFO StartupInfo;// 创 建 进 程 所 需 的 信 息 结 构 变 量 GetStartupInfo(&StartupInfo); StartupInfo.lpReserved=NULL; StartupInfo.lpDesktop=NULL; StartupInfo.lpTitle=NULL; StartupInfo.dwX=0; StartupInfo.dwY=0; StartupInfo.dwXSize=200; StartupInfo.dwYSize=300; StartupInfo.dwXCountChars=500; StartupInfo.dwYCountChars=500; StartupInfo.dwFlags=STARTF_USESHOWWINDOW; StartupInfo.wShowWindow=SW_HIDE; // 说 明 进 程 将 以 隐 藏 的 方 式 在 后 台 执 行 StartupInfo.cbReserved2=0; StartupInfo.lpReserved2=NULL; StartupInfo.hStdInput=stdin; StartupInfo.hStdOutput=stdout; StartupInfo.hStdError=stderr; LPTSTR lpBuffer; UINT uSize; HANDLE hHeap; uSize=(GetCurrentDirectory(0,NULL))*sizeof(TCHAR); hHeap=GetProcessHeap(); lpBuffer=(LPSTR)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,uSize); GetCurrentDirectory(uSize,lpBuffer); // 得 知 当 前 目 录 信 息, 以 便 根 据 需 要 变 换 目 录 if (lpBuffer!=BatPath) //diferent dir SetCurrentDirectory(BatPath); // 创 建 进 程 if (CreateProcess(lpApplicationName,NULL,NULL, NULL,FALSE,CREATE_DEFAULT_ERROR_MODE, NULL,NULL,&StartupInfo,&pro_info)) { MSG Message; DeleteFile(ExitFlag); SetTimer(1,100,NULL);// 设 置 计 时 器 Search=TRUE; while(Search) { if (::PeekMessage(&Message,NULL,0,0,PM_REMOVE)) { ::TranslateMessage(&Message); ::DispatchMessage(&Message); } } // 进 程 结 束 前 后 的 处 理 工 作 DWORDExitCode; if (!GetExitCodeProcess(pro_info.hProcess,&ExitCode)) AfxMessageBox("GetExitCodeProcess is Failed!"); if (!TerminateProcess(pro_info.hProcess,(UINT)ExitCode)) // 终 止 进 程 AfxMessageBox("TerminateProcess is Failed!"); if (!CloseHandle(pro_info.hProcess)) // 释 放 被 终 止 进 程 的 句 柄 AfxMessageBox("CloseHandle is Failed!"); KillTimer(1);// 撤 消 计 时 器 } else AfxMessageBox("Process Is Not Created!"); SetCurrentDirectory(lpBuffer);// 回 复 到 原 来 的 目 录 下 } 同 时 按 下Ctrl 和W 键 或 直 接 单 击 工 具 条 上 的ClassWizard 按 钮, 打 开ClassWizard 对 话 框。 在 类 名(Class name) 列 表 框 中 选 择 需 要 调 用ARJ.EXE 进 行 压 缩/ 解 压 缩 的 类, 在Object IDs 列 表 框 中 选 择 该 类 的 类 名 后, 在 消 息(Messages) 列 表 框 中 选 择WM_TIMER 消 息 并 双 击 它, 这 时ClassWizard 就 会 在 该 类 中 加 入 一 个OnTimer() 函 数。 该 函 数 将 以 一 定 的 时 间 间 隔 检 查 压 缩/ 解 压 缩 程 序 是 否 已 经 执 行 完 毕, 即 检 查 作 为 标 志 的 临 时 文 件 是 否 已 经 存 在, 并 及 时 修 改 状 态 变 量“Search”, 以 便 通 知RunBat() 函 数 结 束 进 程。 void CMyCompress::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default CFile file; CFileException Error; if (file.Open(ExitFlag,CFile::modeRead,&Error)) { Search=FALSE; file.Close(); } } 自 编 删 除 目 录 及 其 下 属 文 件 的 函 数 ---- 高 版 本 的MS-DOS 和Windows 95 都 提 供 了 一 个 可 以 删 除 一 个 或 多 个 目 录 及 其 下 属 文 件 和 目 录 的 命 令, 即DeleteTree 命 令。 然 而, 无 论 在MFC 类 库 还 是 在Win32 函 数 库 中, 都 没 有 相 应 的 函 数 与 之 对 应。 这 样, 当 我 们 在 自 己 设 计 的 应 用 程 序 中 需 要 用 到DeleteTree 的 功 能 时, 自 然 想 到 的 方 法 是 通 过 进 程 调 用 或 者 系 统 调 用 的 方 式( 正 如 上 面 部 分 所 述 的 那 样) 调 用MD-DOS 或Windows 95 下 的DeleteTree 命 令。 然 而,Win32 函 数 库 已 经 为 我 们 提 供 了 多 种 用 于 文 件 和 目 录 操 作 的 函 数, 利 用 它 们 不 难 设 计 出 自 己 的DeleteTree() 函 数。 ---- 读 者 读 到 这 里, 也 许 会 感 到 有 些 疑 惑, 为 什 么 第 六 部 分 强 调 进 程 调 用 优 于 自 我 设 计 的 函 数, 而 这 一 部 分 又 反 了 过 来 ? 是 的, 在 通 常 情 况 下, 调 用 应 用 程 序 内 部 的 函 数 比 使 用 进 程 或 者 调 用 外 部 函 数 更 灵 活 并 且 可 以 提 高 执 行 效 率, 也 便 于 修 改。 所 以, 象DeleteTree() 这 样 的 功 能, 利 用 现 有 的 函 数 并 不 难 实 现, 自 然 就 最 好 通 过 内 部 函 数 的 方 式 来 完 成。 然 而, 象 设 计 一 个 压 缩/ 解 压 缩 这 样 的 函 数 的 工 作 量, 并 不 比 通 过 进 程 调 用 来 使 用 现 成 品 的 开 销 更 合 算, 因 为 它 至 少 需 要 我 们 了 解 压 缩/ 解 压 缩 的 复 杂 算 法, 而 且 调 试 和 维 护 它 也 需 要 一 定 代 价。 于 是, 这 个 时 候, 还 是 采 用“ 拿 来 主 义” 为 好。 ---- 下 面, 给 出 我 自 己 设 计 的DeleteTree() 函 数, 仅 供 参 考。 BOOL DeleteTree(CString DirName) { //成功:返回TRUE;否则,返回FALSE BOOL Result; Result=PreRemoveDirectory(DirName) && RemoveDirectory(DirName); return Result; } BOOL PreRemoveDirectory(CString DirName) {//成功:返回TRUE;否则,返回FALSE LPTSTR lpBuffer; UINT uSize; CString fileName; HANDLE hHeap; BOOL result; HANDLE hFindFile; WIN32_FIND_DATA FindFileData; uSize=(GetCurrentDirectory(0,NULL))*sizeof(TCHAR); hHeap=GetProcessHeap(); lpBuffer=(LPSTR)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,uSize); GetCurrentDirectory(uSize,lpBuffer); if (lpBuffer!=DirName) {//调整当前目录 SetCurrentDirectory(DirName); } hFindFile=FindFirstFile("*.*",&FindFileData); CString tFile; if (hFindFile!=INVALID_HANDLE_VALUE) { do { tFile=FindFileData.cFileName; if ((tFile==".")||(tFile=="..")) continue; if (FindFileData.dwFileAttributes== FILE_ATTRIBUTE_DIRECTORY){ if (DirName[DirName.GetLength()-1]!='\\') PreRemoveDirectory(DirName+'\\'+tFile); else PreRemoveDirectory(DirName+tFile); if (!RemoveDirectory(tFile)) result=FALSE; else result=TRUE; } else if (!DeleteFile(tFile)) result=FALSE; else result=TRUE; } while (FindNextFile(hFindFile,&FindFileData)); FindClose(hFindFile); } else { SetCurrentDirectory(lpBuffer); return FALSE; } SetCurrentDirectory(lpBuffer); //回复到原来的目录下 return result; } 如 何 得 到 并 修 改 各 驱 动 器 的 信 息 ---- 在 设 计 和 文 件 输 入/ 输 出 有 关 的 应 用 程 序 时, 我 们 很 可 能 在 输 入/ 输 出 文 件 前, 需 要 了 解 一 下 源 驱 动 器 或 者 目 标 驱 动 器 的 各 项 信 息, 比 如 是 否 有 磁 盘 在 软 驱 中, 它 是 否 已 打 开 写 保 护, 以 及 现 有 磁 盘 的 容 量 等。 遗 憾 的 是,MFC 类 库 中 没 有 提 供 支 持 这 些 功 能 的 类, 所 以 我 们 只 能 通 过 Win32 提 供 的 函 数 来 完 成 我 们 的 要 求。 下 面, 我 根 据 自 己 的 编 程 实 践, 通 过 几 段 程 序, 来 说 明 如 何 利 用Win32 提 供 的 函 数 实 现 对 驱 动 器 的 操 作。 读 者 可 以 根 据 自 己 的 需 要, 把 介 绍 的 函 数 稍 加 修 改 后, 即 可 插 入 到 自 己 设 计 的 应 用 程 序 中 去。 下 面 程 序 的 功 能 是 搜 索 计 算 机 中 所 有 驱 动 器, 选 择 出 其 中 软 盘 驱 动 器 的 驱 动 器 号, 依 次 加 入 到 一 个 下 拉 列 表 框 中。 void FindDriverInfo() { CComboBox* Driver=(CComboBox*)GetDlgItem(IDC_DRIVER); DWORD dwNumBytesForDriveStrings; HANDLE hHeap; LPSTR lp; CString strLogdrive; int nNumDrives=0, nDriveNum; dwNumBytesForDriveStrings=GetLogicalDriveStrings(0,NULL) *sizeof(TCHAR);//实际存储驱动器号的字符串长度 if (dwNumBytesForDriveStrings!=0) { hHeap=GetProcessHeap(); lp=(LPSTR)HeapAlloc(hHeap,HEAP_ZERO_MEMORY, dwNumBytesForDriveStrings);// GetLogicalDriveStrings(HeapSize(hHeap,0,lp),lp); StringBox.SetSize(dwNumBytesForDriveStrings/sizeof(TCHAR)+1); while (*lp!=0) { if (GetDriveType(lp)==DRIVE_REMOVABLE){ Driver->AddString(lp); StringBox[nNumDrives]=lp; nNumDrives++; } lp=_tcschr(lp,0)+1; } } else AfxMessageBox("Can't Use The Function GetLogicalDriveStrings!"); } 下 面 介 绍 的EmptyDiskSpace() 函 数 主 要 负 责 清 空 指 定 驱 动 器 中 的 磁 盘, 同 时 它 还 负 责 记 录 指 定 驱 动 器 中 磁 盘 的 容 量, 并 得 到 该 磁 盘 的 序 列 号。 在 该 函 数 中, 还 将 调 用 第 七 部 分 提 到 的PreRemoveDirectory() 函 数, 来 完 成 清 空 工 作。 BOOL EmptyDiskSpace(CString Driver) { BOOL result=TRUE; DWORDSectorsPerCluster; // address of sectors per cluster DWORDBytesPerSector; // address of bytes per sector DWORDNumberOfFreeClusters; // address of number of free clusters DWORDTotalNumberOfClusters; DWORDTotalBytes; DWORDFreeBytes; int bContinue=1; char DiskVolumeSerialNumber[30]; //存储驱动器内当前磁盘的序列号 LPCTSTRlpRootPathName; // address of root directory of the file system LPTSTRlpVolumeNameBuffer=new char[12]; // address of name of the volume DWORDnVolumeNameSize=12; // length of lpVolumeNameBuffer DWORD VolumeSerialNumber; // address of volume serial number DWORD MaximumComponentLength; // address of system's maximum filename length DWORD FileSystemFlags; // address of file system flags LPTSTRlpFileSystemNameBuffer=new char[10]; // address of name of file system DWORDnFileSystemNameSize=10; // length of lpFileSystemNameBuffer lpRootPathName=Driver; while (1){ if (GetDiskFreeSpace(Driver, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters)) {//驱动器中有磁盘 TotalBytes=SectorsPerCluster*BytesPerSector *TotalNumberOfClusters;//磁盘总容量 FreeBytes=SectorsPerCluster*BytesPerSector *NumberOfFreeClusters;//磁盘空闲空间容量 GetVolumeInformation(lpRootPathName, lpVolumeNameBuffer, nVolumeNameSize, &VolumeSerialNumber, &MaximumComponentLength, &FileSystemFlags, lpFileSystemNameBuffer, nFileSystemNameSize); sprintf(DiskVolumeSerialNumber,"%X",VolumeSerialNumber); //得到驱动器内当前磁盘的序列号 SetmTotalBytes(TotalBytes/1024);//存储指定驱动器中磁盘的容量 if (TotalBytes!=FreeBytes){//当磁盘总容量不等于空闲空间容量时, 应该执行清空操作 while (bContinue) { if ((bContinue==2)||(MessageBox ("在驱动器 "+m_Driver+"中的磁盘尚存有数据. \n您愿意让系统为您删除它们吗?", "提问",MB_YESNO|MB_ICONQUESTION)==IDYES)) if (!PreRemoveDirectory(Driver))//无法执行清空操作 if (MessageBox("因某种原因系统无法删除 在驱动器 "+m_Driver+"中的磁盘上的数据. \n请检查磁盘是否没有关闭写保护. \n您愿意再试一次吗?", "问题",MB_YESNO|MB_ICONERROR)==IDYES) { bContinue=2; continue; } else { bContinue=0; result=FALSE; } else { MessageBox("成功删除磁盘上的数据!", "提示信息",MB_OK|MB_ICONINFORMATION); bContinue=0; result=TRUE; } else {//THE FIRST IF'S ELSE bContinue=0; result=FALSE; } } } else result=TRUE; break; } else { if (MessageBox("没有磁盘在驱动器 "+m_Driver+"中. \n您愿意插入一张磁盘再来一次吗?", "问题",MB_YESNO|MB_ICONASTERISK)==IDYES) continue; else break; } }//END OF WHILE return result; } 在MS-DOS 和Windows95 中, 磁 盘 卷 标 最 多 由11 个 字 符 组 成, 并 且 字 母 的 大 小 写 不 加 区 分。 当 需 要 设 定 指 定 驱 动 器 中 磁 盘 的 卷 标 时, 只 要 调 用Win32 的SetVolumeLabel() 函 数 即 可, 并 在 第 一 个 参 数 中 指 明 磁 盘 所 在 的 驱 动 器 号, 在 第 二 个 参 数 中 指 明 新 的 卷 标 号。 例 如, SetVolumeLabel(DriverNum, NewVolumeLabel)。 中国计算机世界出版服务公司版权所有 Java 语 言 的 面 向 对 象 特 性 ---- Java 语 言 是Sun 公 司1995 年 推 出 的 新 型 面 向 对 象 程 序 设 计 语 言(OOPL,Object Oriented Programming Language)。 它 以C + + 为 蓝 本, 保 留 了C + + 的 许 多 面 向 对 象 特 性, 并 改 进 了 一 些 机 制, 如 封 装 主 函 数、 串 和 数 组 对 象 化 等, 摒 弃 了 可 能 引 起 二 义 性、 冗 余 和 存 在 不 安 全 隐 患 的 语 言 机 制, 如 运 算 符 重 载、 多 重 继 承 以 及 类 型 自 动 转 换 等, 使 其 面 向 对 象 特 性 比 C + + 更 突 出。 此 外, 为 满 足 网 络 计 算 的 需 要,Java 又 增 加 了 分 布 式、 动 态 性、 并 行 性、 可 移 植 性 等 特 性, 取 消 了C + + 中 指 针、 指 针 运 算 等 不 利 于 分 布 式 计 算 的 机 制, 为 在 分 布 式 环 境 下 开 发 动 态 可 扩 展 的 应 用 提 供 了 便 利 条 件。 对 面 向 对 象 计 算 模 型 的 支 持 ---- 一 般 认 为 面 向 对 象 有 五 大 特 征: 抽 象、 封 装、 继 承、 多 态 和 动 态 束 定。 一 种 OOPL 至 少 应 支 持 这 些 特 征, 下 面 依 次 分 析Java 语 言 对 以 上 五 点 的 支 持。 ---- 1. 抽 象 和 封 装 ---- 客 观 世 界 中 的 对 象 均 具 有 属 性 和 行 为, 映 射 到 程 序 世 界 中, 属 性 表 示 数 据, 行 为 代 表 操 作。 所 谓 封 装, 就 是 用 一 个 自 主 式 框 架 将 数 据 集 和 操 作 集 组 织 在 一 起, 构 成 一 个 程 序 实 体, 即 程 序 世 界 中 的 对 象。 在 面 向 对 象 概 念 中, 对 象 是 支 持 封 装 的 手 段, 是 封 装 的 基 本 单 位。 数 据 集 描 述 对 象 的 状 态, 对 象 行 为 执 行 操 作) 的 结 果 引 起 状 态 改 变。 对 象 内 部 的 数 据 和 操 作 可 以 公 有(public) 也 可 以 私 有(private)。 私 有 的 数 据 和 操 作 只 能 被 对 象 自 身 访 问, 公 有 的 操 作 和 数 据 则 可 被 其 他 对 象 访 问。 每 个 对 象 可 以 接 收 一 组 消 息, 对 象 解 释 一 条 消 息, 执 行 一 个 相 应 的 操 作。 一 个 面 向 对 象 程 序 的 执 行 就 是 系 统 中 一 系 列 对 象 之 间 相 互 发 消 息 通 信 的 过 程。 因 此, 面 向 对 象 的 程 序 设 计 模 型 可 以 概 括 为: 程 序= 对 象 + 消 息。 ---- 封 装 和 抽 象 是 密 不 可 分 的。 在Java 语 言 中, 对 象 由 类(class) 来 描 述, 每 个 对 象 均 有 一 个 相 应 的 类。 类 是 具 有 相 似 特 征 的 对 象 模 板, 是 对 具 体 对 象 的 抽 象。 对 象 通 过 实 例 化 一 个 类 而 得 以 创 建, 被 创 建 的 对 象 称 为 类 的 一 个 实 例(Instance)。 类 中 封 装 了 对 象 的 属 性 和 方 法, 对 象 的 属 性 既 可 以 是 常 量 也 可 以 是 其 他 类 的 实 例, 对 象 的 方 法 用 函 数 和 过 程 来 表 示。 ---- 与C + + 不 同,Java 更 纯 正, 即 语 言 的 任 何 方 面 都 是 基 于 消 息 或 基 于 对 象 的, 所 有 数 据 类 型, 无 论 简 单 还 是 复 杂, 均 为 对 象 类。 可 以 从 三 个 方 面 来 说 明Java 的 纯 面 向 对 象 特 性: 首 先,Java 实 现 了ANSI C 中 所 有 数 据 类 型, 并 且 为 这 些 基 本 数 据 类 型 定 义 了 对 象 类, 如 整 型int 的 类 为Integer。 其 次, 在Java 语 言 中 字 符 串 和 数 组 也 是 对 象, 它 们 分 别 用 字 串 类 (String) 和 相 应 类 的 数 组 类 来 描 述, 例 如, 如 果 你 定 义 了A 类, 则Java 自 动 为 你 定 义A 的 数 组 类A[]。 最 后, 同Smalltalk 类 似,Java 语 言 中 的 类 也 是 对 象, 类 可 以 用 元 类 来 描 述。 元 类 是Java 内 定 义 的 一 种 特 殊 类, 是 对 类 的 抽 象, 它 可 以 用 来 实 现Java 的 动 态 特 性 — — 即 时 装 入 类, 生 成 实 例。 ---- 此 外,Java 语 言 可 以 通 过 前 置 修 饰 符 来 标 明 对 象 属 性 和 方 法 的 可 访 问 程 度。 其 中 公 共(public) 属 性 和 方 法 可 以 被 任 何 类 的 实 例 访 问; 友 元(friendly) 属 性 和 方 法 只 能 被 同 一 包(package) 中 类 的 实 例 访 问; 受 保 护(protected) 的 属 性 和 方 法 只 能 由 对 象 本 身 及 其 子 类 的 实 例 访 问; 私 有 属 性 和 方 法 只 能 由 对 象 本 身 访 问。 属 性 和 方 法 的 访 问 修 饰 符 体 现 了 面 向 对 象 中 的 封 装 原 则。 ---- 2. 继 承 性 ---- 面 向 对 象 的 继 承 性 意 味 着 在 开 发 新 类 时 可 以 只 说 明 它 与 另 一 个 已 存 在 的 类 的 不 同 之 处, 新 类 继 承 已 存 在 类 的 属 性 和 方 法。 在 继 承 层 次 中, 父 类 也 叫 基 类, 子 类 也 叫 派 生 类。 一 个 派 生 类 只 有 一 个 基 类 称 为 单 继 承, 若 有 多 个 基 类 则 称 为 多 继 承。 如 果 将 基 类 及 其 派 生 类 组 成 的 类 体 系 存 入 库 中 则 形 成 类 库。 类 库 为 软 件 开 发 带 来 莫 大 方 便, 程 序 设 计 的 主 要 工 作 就 是 浏 览 类 库, 选 择 合 适 的 类 加 以 重 用, 这 样 减 少 了 代 码 重 复, 减 轻 了 开 发 的 工 作 量。 ---- 继 承 是Java 语 言 的 核 心 思 想, 它 的 基 本 类 库 作 为 语 言 自 身 的 一 部 分 而 存 在。 在Java 中, 无 论 系 统 类 库 中 已 存 在 的 类 还 是 用 户 定 义 的 新 类 都 直 接 或 间 接 地 继 承 于 一 个 公 共 基 类Object。Objetc 定 义 了 所 有 类 实 例 的 若 干 公 共 的 行 为: 实 例 间 复 制、 比 较 以 及 线 程 操 作 等。 ---- Java 语 言 在 类 之 间 通 过extend 关 键 字 实 现 单 继 承, 一 个 类 仅 能 有 一 个 基 类, 因 此Java 的 核 心 继 承 体 系 是 树 状 结 构。 此 外,Java 还 引 入 了 一 种 新 的 语 言 机 制 — — 接 口(Interface)。 在Java 中, 接 口 是 一 种 特 殊 的 抽 象 类, 它 仅 能 声 明 常 量 和 抽 象 方 法, 而 没 有 方 法 的 具 体 实 现。 方 法 的 具 体 实 现 在 实 现(Implements) 接 口 的 类 中 定 义。 一 个 类 除 了 继 承 基 类 外, 还 可 以 实 现 多 个 接 口, 并 且 处 在 不 同 继 承 分 枝 的 类 可 以 实 现 同 一 接 口, 这 样 就 间 接 地 实 现 了 多 重 继 承。 ---- 3. 多 态 性 和 动 态 束 定 ---- 一 个 名 字 代 表 多 种 类 型, 多 种 类 型 的 变 量, 或 多 个 不 同 语 义 的 函 数 或 过 程 叫 多 态。 我 们 经 常 会 遇 到 不 同 类 型 的 对 象 具 有 相 同 行 为, 但 行 为 内 容 不 同 的 情 况, 比 如 汽 车 和 飞 机 都 可 以 运 动, 但 它 们 具 体 运 动 的 方 式 并 不 相 同, 这 就 是 面 向 对 象 中 的 多 态。 ---- Java 主 要 在 四 个 方 面 体 现 多 态 性: 继 承、 重 载(overloading)、 覆 盖(overriding) 和 接 口。 在 继 承 机 制 中, 基 类 定 义 的 操 作 适 用 于 类 的 对 象, 这 种 多 态 也 称 为 包 容 多 态, 是 最 简 单 的 多 态 方 法。 象C + + 一 样,Java 语 言 在 同 一 个 类 中 支 持 方 法 重 载, 即 方 法 相 同, 但 参 数 类 型、 个 数 不 同。 例 如, 一 个Java 类 可 以 定 义 多 个 构 造 函 数, 在 实 例 化 中, 根 据 不 同 参 数 调 用 同 名 方 法 的 不 同 实 现 版 本, 重 载 也 是 多 态 的 一 种 类 型。 覆 盖 和 重 载 是 完 全 不 同 的 概 念,Java 的 方 法 重 载 在 同 一 个 类 中, 而 方 法 覆 盖 则 在 有 继 承 关 系 的 不 同 类 中, 即 在 有 继 承 关 系 的 类 之 间 实 现 多 态。 顾 名 思 义, 覆 盖 不 仅 方 法 名 相 同, 且 变 元 数 目 和 类 型, 方 法 返 回 类 型 都 相 同, 即 在 派 生 类 中 重 新 实 现 基 类 的 某 一 方 法。 此 外,Java 语 言 还 可 以 通 过 接 口 在 没 有 直 接 联 系 的 类 之 间 实 现 多 态。 前 面 提 到, 接 口 中 的 方 法 是 抽 象 方 法, 有 声 明 而 没 有 具 体 实 现, 任 何 实 现 接 口 的 类 都 要 具 体 实 现 接 口 的 方 法。 这 样, 多 个 实 现 同 一 接 口 的 类 就 有 了 同 名 的 方 法, 不 同 的 方 法 实 现, 体 现 了 多 态 性。 重 载、 覆 盖 和 接 口 实 现 的 多 态 都 是 同 一 方 法 配 备 的 多 个 方 法 体, 它 们 统 称 为 重 载 多 态。 Java 语 言 的 动 态 特 性 ---- 多 数 面 向 对 象 程 序 设 计 语 言 在 系 统 设 计 编 制 阶 段 都 能 充 分 体 现OO 思 想, 但 却 很 难 将OO 延 伸 至 系 统 运 行 和 维 护 阶 段。 这 主 要 是 因 为 多 数 语 言 都 采 用 静 态 链 连 机 制, 即 在 编 译 时 就 将 组 成 系 统 的 各 模 块 和 类 链 连 组 合 成 一 个 整 体, 破 坏 了 系 统 的 模 块 性。 在 系 统 运 行 和 维 护 阶 段, 如 果 某 些 类 进 行 了 修 改 或 升 级, 整 个 系 统 必 须 重 新 编 译 才 能 利 用 类 新 增 或 修 改 的 功 能, 未 能 体 现 面 向 对 象 的 优 势。 此 外, 随 着 网 络 技 术 的 发 展, 计 算 环 境 正 迅 速 由 单 主 机 集 中 式 向 网 络 分 布 式 转 变。 在 分 布 式 环 境 中, 系 统 运 行 情 况 更 为 复 杂, 维 护 越 发 困 难, 特 别 是 在 某 些 情 况 下, 系 统 一 旦 运 行 一 般 就 不 能 停 止, 例 如 金 融 机 构 的 联 机 事 务 处 理 系 统 等。 如 何 在 运 行 中 动 态 的 进 行 系 统 修 改 和 升 级 便 成 为 迫 切 需 要 解 决 的 问 题。 ---- Java 语 言 的 动 态 特 性 是 对 面 向 对 象 设 计 的 延 伸, 这 种 特 性 使 得 用Java 开 发 的 系 统 能 够 适 应 不 断 变 化 的 执 行 环 境, 这 正 可 以 解 决 上 述 问 题。 动 态 特 性 的 技 术 核 心 是 滞 后 联 编, 滞 后 联 编 使Java 将OO 特 点 延 伸 到 系 统 运 行 阶 段。 我 们 知 道, Java 程 序 的 基 本 组 成 单 位 是 类, 编 译 时 每 个 类 被 分 别 编 译 成 相 应 的 类 文 件, 这 样 一 个 系 统 由 若 干 个 类 文 件 组 成, 系 统 的 模 块 性 得 以 保 留, 在 系 统 运 行 时, 类 文 件 按 程 序 运 行 需 要 被 动 态 装 载, 即 插 即 用(Plug And Play)。 利 用 这 种 特 性, 系 统 的 支 持 类 修 改 之 后, 相 应 的 应 用 程 序 不 必 重 新 编 译, 也 一 样 可 以 利 用 修 改 后 类 的 功 能。 如 果 类 文 件 是 分 布 在 网 络 环 境 下,Java 也 可 以 利 用 这 种 特 性 在 分 布 式 环 境 中 动 态 维 护 应 用 程 序 及 其 支 持 类 库 之 间 的 一 致 性。 小 结 ---- Java 语 言 是Sun 公 司 开 发 的 新 型 面 向 对 象 程 序 设 计 语 言。 它 以 简 单 易 学、 概 念 清 晰 的 纯 面 向 对 象 特 性 见 长, 非 常 适 合 于 学 习 面 向 对 象 程 序 设 计。 中国计算机世界出版服务公司版权所有 实 现JAVA 的 动 态 类 载 入 机 制 车 飞(chf@publicyx.jn.sd.cn) ---- 作 为 充 分 利 用Java 的 动 态 类 载 入 机 制 的 最 好 例 子, 带 有Java 扩 展 的Web 浏 览 器 根 据 请 求 从 网 络 或 本 地 文 件 系 统 中 动 态 加 载Java applet( 遵 循 一 定 规 则 的Java 小 应 用 程 序 类), 然 后 在 本 地 系 统 中 执 行 它, 大 大 增 强 了 主 页 的 功 能。 ---- 其 实,Java 本 身 就 是 一 种 极 具 动 态 性 的 语 言。 类 似 Windows 的 动 态 链 接 库(DLL),Java 应 用 程 序 总 是 被 编 译 成 若 干 个 单 独 的class 文 件, 程 序 执 行 时 根 据 需 要 由 Java 虚 拟 机 动 态 载 入 相 应 的 类。 这 种 机 制 使 编 写 动 态 的 分 布 式 应 用 程 序 成 为 可 能: 我 们 可 以 在 客 户 端 编 写 自 己 的 类 载 入 器, 而 真 正 执 行 的 程 序 却 存 放 在 本 地、 局 域 网 或 世 界 另 一 端 的 主 机 上。 下 面 将 介 绍 如 何 在 自 己 的 应 用 程 序 中 实 现Java 的 动 态 类 载 入 机 制。 与 动 态 类 载 入 有 关 的 系 统 类 ---- 为 支 持 动 态 类 载 入 机 制, 在 系 统 类 组java.lang 中 提 供 了 两 个 类:Class 类 和ClassLoader 类。 ---- 1、 类java.lang.Class。 在Java 虚 拟 机 中, 每 一 个 类 或 接 口 都 是 由Class 类 来 操 纵 的, 它 不 能 被 显 式 的 实 例 化, 必 须 用 其 他 方 法 来 获 取Class 类 的 对 象。 动 态 类 载 入 机 制 的 关 键 一 步 在 于 如 何 获 得 指 定 类 的Class 类 型 的 对 象。 相 关 方 法 主 要 有: ---- public static Class forName(String className) ---- 这 是 一 个 静 态 方 法, 它 获 取 指 定 名 字 的 类 的Class 类 型 对 象, 类 名 可 以 是 象“sun.applet.Applet” 这 样 的 字 符 串, 但 不 能 带 有 路 径 或 网 络 地 址 等 信 息。 这 是 从 本 地 系 统 中 动 态 载 入 类 的 最 方 便 的 办 法。 ---- public Object newInstance() ---- 这 是 最 重 要 的 一 个 方 法, 它 建 立 由Class 类 型 对 象 描 述 的 指 定 类 的 实 例。 ---- 下 面 是 一 个 用forName() 和newInstance() 方 法 实 现 动 态 类 载 入 的 代 码,share 类 包 含 一 个 接 口, 详 细 内 容 将 在 第 三 部 分 中 解 释。 try{ //根据类名建立Class类型的对象。 Class cc =Class.forName("类名")); //建立被载入类类的实例并强制类型转换, 值赋给share类型的变量。 share oo=((share)cc).newInstance(); //调用该类的方法进行工作。 } catch (Exception ex){ //如果发生例外,则进行相应处理。 }; ---- 2、 类java.lang.ClassLoader。 这 是 一 个 抽 象 类, 如 果 打 算 运 用 它, 必 须 继 承 它 并 重 写 它 的loadClass() 方 法。 其 主 要 方 法 有: ---- protected ClassLoader(); ---- 这 是 一 个 建 构 元, 可 以 用 它 建 立 一 个ClassLoader 类 的 实 例。 注 意 继 承 这 个 类 的 类 必 须 重 写 这 个 方 法, 而 不 能 使 用 缺 省 的 建 构 元。 ---- protected abstract Class loadClass(String name, boolean resolve) ---- 载 入 指 定 的 类 数 据, 建 立Class 类 型 的 对 象 并 根 据 需 要 解 析 它。 这 是 一 个 抽 象 方 法, 大 家 必 须 在 自 己 的 子 类 中 重 写 这 个 方 法, 重 写 的 规 则 可 以 参 考 第 三 部 分 的 例 子。 ---- protected final Class defineClass(byte data[], int offset, int length) ---- 将 字 节 数 组 中 的 数 据 定 义 为Class 类 型 的 对 象, 字 节 数 组 的 格 式 由 虚 拟 机 规 定。 ---- protected final Class findSystemClass(String name) ---- 根 据 指 定 的 类 名 载 入 类, 它 会 自 动 在 当 前 目 录 和 环 境 变 量“CLASSPATH” 指 定 的 路 径 中 寻 找, 如 果 找 不 到, 则 会 抛 出ClassNotFoundException 例 外。 ---- protected final void resolveClass(Class c) ---- 通 过 载 入 与 指 定 的 类 相 关 的 所 有 类 来 解 析 这 个 类, 这 必 须 在 类 被 使 用 之 前 完 成。 扩 充ClasslLader 类 以 实 现 动 态 类 载 入 ---- 理 解 动 态 类 载 入 机 制 的 最 好 办 法 是 通 过 例 子, 下 面 这 个 完 整 的 例 子 由 四 个 类 组 成, 分 别 解 释 如 下: ---- 1、MyClassLoader 类 是ClassLoader 类 的 子 类, 它 重 写 了 loadClass 方 法, 实 现 了 将 网 络 上 用URL 地 址 指 定 的 类 动 态 载 入, 取 得 它 的Class 类 型 对 象 的 功 能。 读 者 可 根 据 自 己 载 入 类 的 具 体 方 式 改 写 下 面 的 代 码。 import java.io.*; import java.util.*; import java.net.*; public class MyClassLoader extends ClassLoader { //定义哈希表(Hashtable)类型的变量, 用于保存被载入的类数据。 Hashtable loadedClasses; public MyClassLoader() { loadedClasses = new Hashtable(); } public synchronized Class loadClass(String className, boolean resolve) throws ClassNotFoundException { Class newClass; byte[] classData; //检查要载入的类数据是否已经被保存在哈希表中。 newClass = (Class) loadedClasses.get(className); //如果类数据已经存在且resolve值为true,则解析它。 if (newClass != null){ if (resolve) resolveClass(newClass); return newClass; } ---- /* 首 先 试 图 从 本 地 系 统 类 组 中 载 入 指 定 类。 这 是 必 须 的, 因 为 虚 拟 机 将 这 个 类 载 入 后, 在 解 析 和 执 行 它 时 所 用 到 的 任 何 其 他 类, 如java.lang.System 类 等, 均 不 再 使 用 虚 拟 机 的 类 载 入 器, 而 是 调 用 我 们 自 制 的 类 载 入 器 来 加 载。*/ try { newClass = findSystemClass(className); return newClass; } catch (ClassNotFoundException e) { System.out.println(className+" is not a system class!"); } //如果不是系统类, 则试图从网络中指定的URL地址载入类。 try { //用自定义方法载入类数据, 存放于字节数组classData中。 classData = getClassData(className); //由字节数组所包含的数据建立一个class类型的对象。 newClass = defineClass(classData, 0, classData.length); if (newClass == null) throw new ClassNotFoundException(className); } catch (Exception e) { throw new ClassNotFoundException(className); } //如果类被正确载入, 则将类数据保存在哈希表中,以备再次使用。 loadedClasses.put(className, newClass); //如果resolve值为true,则解析类数据。 if (resolve){ resolveClass(newClass); } return newClass; } //这个方法从网络中载入类数据。 protected byte[] getClassData(String className) throws IOException { byte[] data; int length; try { //从网络中采用URL类的方法 载入指定URL地址的类的数据。 URL url = new URL(className.endsWith(".class") ? className : className + ".class"); URLConnection connection = url.openConnection(); InputStream inputStream = connection.getInputStream(); length = connection.getContentLength(); data = new byte[length]; inputStream.read(data); inputStream.close(); return data; } catch(Exception e) { throw new IOException(className); } } } ---- 2、 由 于Java 是 强 类 型 检 查 语 言, 通 过 网 络 载 入 后 的 类 被 实 例 化 后 只 是 一 个Object 类 型 的 对 象, 虚 拟 机 并 不 知 道 它 包 含 那 些 方 法, 应 从 哪 个 方 法 开 始 执 行。 因 此, 可 以 被 动 态 载 入 的 类 必 须 继 承 某 一 个 抽 象 类 或 实 现 某 一 个 接 口, 因 为 父 类 只 能 有 一 个, 所 以 通 常 用 实 现 特 定 接 口 的 办 法。 下 面 的 代 码 定 义 了 一 个 接 口 类share 和 它 的 方 法start()。 public interface share { public void start(String[] option); } ---- 3、TestClassLoader 类 通 过 使 用MyClassLoader 类 的loadClass() 方 法, 将 指 定URL 地 址 的 类 载 入 并 在 本 地 系 统 执 行 它, 实 现 了 类 的 动 态 载 入。 注 意 在 执 行 被 载 入 类 的 方 法 前 一 定 要 将 它 进 行 强 制 数 据 类 型 转 换。 public class TestClassLoader { public static void main(String[] args){ MyClassLoader ll = new MyClassLoader(); Class cc; Object oo; String ss = "http://kyzser.ydxx/classLoader/Tested.class"; if (args.length != 0) ss = args[0]; try { System.out.println("Loading class "+ss+"..."); //使用重写的方法loadClass()载入类数据。 cc = ll.loadClass(ss); System.out.println("Creat instance..."); //创建Object类型的类实例。 oo = cc.newInstance(); System.out.println("Call start() method..."); //强制类型转换并执行被载入类中的方法。 ((share) oo).start(args); }catch (Exception e) { System.out.println("Caught exception : "+e); } } } ---- 4、Tested 类 很 简 单, 可 以 将 它 放 在 任 何WEB 服 务 器 上, 但 应 注 意 能 动 态 载 入 且 被 执 行 的 类, 一 定 要 实 现 预 先 定 义 的 接 口 中 的 方 法。 下 面 的 例 子 实 现 了 接 口 share 的start 方 法。 public class Tested implements share{ public void start(String[] option){ //填写程序代码。 } } 动 态 类 载 入 机 制 的 几 点 应 用 ---- 1、 开 发 分 布 式 应 用。 这 对 开 发 远 程 的 客 户 端 应 用 程 序 最 有 用, 客 户 端 仅 需 要 安 装 一 些 基 本 的 系 统 和 一 个 能 实 现 动 态 类 载 入 机 制 的 类, 需 要 本 地 系 统 不 存 在 的 功 能 时, 仅 需 要 从 网 络 动 态 载 入 并 执 行 相 应 类 即 可 获 得 特 定 功 能。 因 为 客 户 端 所 使 用 的 总 是 软 件 的 最 新 版 本, 所 以 不 再 存 在 软 件 的 升 级 和 维 护 问 题, 即 实 现 了 所 谓 的“ 零 管 理” 模 式。 ---- 2、 对.class 文 件 加 密。 由 于Java 的 字 节 码(bytecode) 容 易 被 反 编 译, 大 部 分 开 发Java 应 用 程 序 的 公 司 均 担 心 自 己 的 成 果 被 别 人 不 劳 而 获。 其 实 可 以 将 类 文 件 进 行 适 当 的 加 密 处 理, 执 行 时 使 用 自 己 的 类 载 入 器 进 行 相 应 的 解 密, 就 可 以 解 决 这 个 问 题。 ---- 3、 使 第 三 方 开 发 者 易 于 扩 展 你 的 应 用。 从 前 面 可 知, 所 有 可 以 被 你 的 类 载 入 器 动 态 载 入 并 被 执 行 的 类, 必 须 继 承 你 定 义 的 类 或 实 现 你 定 义 的 接 口, 这 样, 你 可 以 制 订 一 些 规 则, 使 其 他 开 发 者 不 必 了 解 你 的 应 用 程 序 也 可 以 扩 充 功 能。 ---- 当 然, 有 利 必 有 弊, 在 网 络 中 使 用 动 态 类 载 入 的 主 要 缺 陷 在 于 安 全 性, 很 难 保 证 不 载 入 不 怀 好 意 的 代 码, 这 个 问 题 要 靠Java 的 安 全 管 理 器 和 适 当 的 加 密 算 法 来 解 决, 已 超 出 本 文 的 讨 论 范 围。 中国计算机世界出版服务公司版权所有 Java RMI 应 用 黄 朝 与 RMI ---- 作 为 一 种 优 秀 的 计 算 平 台,Java 在 许 多 方 面 具 有 其 突 出 的 优 越 性, 其 中 RMI(Remote Method Invoke) 最 典 型 地 展 现 了Java 平 台 强 大 的 分 布 计 算 能 力。 本 文 用 一 个 简 单 的 例 子 说 明RMI 给 分 布 计 算 带 来 的 方 便, 以 及RMI 对 很 多 应 用 领 域 的 重 要 意 义, 如 桌 面 超 级 计 算 的 可 能 性。 ---- 简 言 之,RMI 是 一 种Java 虚 拟 机 之 间 对 象 互 相 调 用 对 方 函 数、 启 动 对 方 进 程 的 一 种 机 制, 用 这 种 机 制, 某 一 台Java 虚 拟 机 上 的 对 象 在 调 用 另 外 一 台Java 虚 拟 机 上 的 函 数 时, 使 用 的 程 序 语 法 规 则 和 在 本 台Java 虚 拟 机 上 对 象 间 的 函 数 调 用 的 语 法 规 则 一 样。 正 是 这 种 机 制 给 分 布 计 算 的 系 统 设 计 和 编 程 都 带 来 了 极 大 的 方 便。 只 要 按 照RMI 规 程 设 计 程 序, 程 序 员 可 以 不 必 再 过 问 RMI 之 下 的 网 络 细 节, 如TCP/IP、Socket 等, 更 不 必 担 心 其 下 面 的 软 硬 件 环 境。 任 意 两 台Java 虚 拟 机 之 间 的 通 讯 完 全 由Java 虚 拟 机 自 己 的RMI 来 负 责。 对 程 序 员 来 讲, 这 两 台Java 虚 拟 机 之 间 完 全 是 透 明 的, 远 程Java 虚 拟 机 上 的 对 象, 使 用 起 来 就 像 近 在 眼 前 一 样。 范 例 ---- 本 文 的 例 子 是 利 用RMI 设 计 的 一 个 简 单 的 网 络 计 算 器, 其 功 能 是 一 个 三 阶 多 项 式 的 求 值, 然 后 画 出 轨 迹。 读 者 如 没 有 时 间, 在 阅 读 时 暂 时 不 必 细 究 其 语 法 细 节, 特 别 是 有 些 用IBM 的VisualAge for Java 自 动 生 成 的 用 户 界 面 代 码, 但 从 该 例 子 的 程 序 结 构 中, 读 者 可 足 以 了 解RMI 简 明 的 风 格。 另 外, 本 文 主 要 从 应 用 的 角 度 讨 论RMI, 省 去 了 对 其 原 理 的 分 析, 感 兴 趣 的 读 者 可 直 接 访 问http://java.sun.com。 ---- 计 算 器 的 设 计 方 法 有 很 多 种, 从 结 构 上 看, 归 纳 起 来, 大 致 有 三 种。 ---- 1、 本 地 机 在 本 机 上 输 入 参 数, 计 算 在 本 机 上 完 成, 结 果 由 本 机 显 示 给 用 户。 ---- 2、 本 地 机 -TCP/IP - 远 程 机 在 本 地 机 上 输 入 参 数, 本 地 机 将 参 数 通 过 网 络 送 给 远 程 机, 远 程 机 启 动 一 个 进 程 计 算 出 结 果, 然 后 将 结 果 通 过 网 络(Socket、 HTTP 等) 送 给 本 地 机, 结 果 由 本 地 机 显 示 给 用 户。 ---- 3、 本 地 机 -RMI -TCP/IP -RMI - 远 程 机 本 地 机 从 远 程 机 上 得 到 一 个 小 程 序(Applet) 用 作 数 据 输 入( 多 项 式 系 数) 和 结 果 显 示, 在 本 地 机 上 输 入 的 数 据 将 作 为 调 用 远 程 机 上 函 数 的 参 数。 该 远 程 函 数 计 算 出 结 果, 反 过 来, 将 该 结 果 作 为 调 用 本 地 机 上 对 象( 如 该Applet) 的 函 数 ( 如 屏 幕 刷 新) 的 参 数 调 用 该 本 地 函 数。 这 样 计 算 结 果 就 自 然 地 被 送 回 来, 显 示 在 本 地 机 上。 ---- 显 然, 第3 种 方 案 是 最 灵 活、 最 优 雅 的 网 络 计 算 模 式, 本 文 的 程 序 正 是 基 于 这 种 模 式。 由 于 篇 幅 所 限, 程 序 没 有 过 多 考 虑 完 备 性, 如 对Exception 只 作 了 简 单 的 处 理。 ---- 程 序 中,ServerManager、 ServerManagerListener 用 于 简 单 控 制RMIServer 的 启 动、 停 止、 退 出。RMIServer 设 计 成 一 个 简 单 的RMI 服 务 器, 其 中: RMIServer(String sMAPServerName) 完 成 服 务 器 的 命 名, 在1099 口 上 作 注 册 登 记 准 备。 startRMI() 的Naming.rebind(“/" +sServerName,this) 启 动 该 服 务 器, 名 称 为“RMIServer", 启 动 后,RMIServer 开 始 在1099 口 上 监 听 来 自 网 络 的 呼 叫。 stopRMI() 的Naming.unbind(sServerName) 用 于 停 止 该 服 务 器。 calculateIT(double[] dA, ClientRemoteInterfacecrInterface) throws RemoteException 是 供 客 户 端Java 虚 拟 机 作 远 程 调 用 的 函 数,dA 是 多 项 式 系 数(a3,a2,a1,a0), 该 多 项 式 定 义 为: ---- F(X)=a3 *X3 +a2 *X2 +a1 *X +a0 crInterface 是 客 户 端Java 虚 拟 机 远 程 调 用 服 务 器 端Java 虚 拟 机 时 作 为 参 数 送 过 来 的 代 表 客 户 端 的 远 程 接 口, 供 服 务 器 端 需 要 时 反 过 来 对 客 户 端 作 远 程 调 用 时 使 用。calculateIT 结 果 计 算 出 来 后, 服 务 器 端 用: ---- crInterface.drawIT(iXY); 语 句 激 活 在 客 户 端 的drawIT(iXY) 函 数。 计 算 结 果iXY 作 为 函 数 参 数 自 动 地 传 送 到 客 户 端。 客 户 端Java 虚 拟 机 靠CalculatorDisplay 这 个Applet 来 激 发 服 务 器 端Java 虚 拟 机 上 的calculateIT 函 数, 浏 览 器( 如HotJava) 从 服 务 器 上 获 得CalculatorDisplay 以 后, 该Applet 的init() 函 数 里 有 两 条 关 键 的 语 句: ---- srInterface = (ServerRemoteInterface)Naming.lookup(“//" +getCodeBase().getHost() +“/" + “RMIServer"); ---- UnicastRemoteObject.exportObject(this); ---- 第 一 句 的 目 的 是 在 提 供 该Applet 的 服 务 器 上 寻 找 名 为RMIServer 的RMI 远 程 对 象, 找 到 以 后, 用srInterface 接 口 表 示; 第 二 句 是 输 出 本 对 象, 即 将 本 对 象 的 远 程 接 口 作 为 远 程 函 数 调 用 的 参 数 传 送 到 服 务 器 端。 当 需 要 调 用( 或 启 动) 服 务 器 端 的calculateIT 函 数 时, 也 只 是 用 简 单 的 下 面 一 条 语 句: ---- srInterface.calculateIT(dA,this); Java 工 具 还 会 自 动 生 成CalculatorDisplay_Skel、 CalculatorDisplay_Stub、RMIServer_Skel、 RMIServer_Stub 文 件, 在 此 可 暂 不 理 会。 前 景 ---- 虽 然 本 文 描 述 的 只 是 一 个 小 小 的 多 项 式 求 值 及 轨 迹 输 出 例 子, 但 不 难 想 象, 计 算 对 象 可 以 是 高 阶 微 分 方 程、 高 阶 矩 阵 运 算 等。 服 务 器 可 以 是 超 级 计 算 机, 在 其 上 可 进 行 诸 如 流 体 力 学 模 型 仿 真、 风 洞 模 拟 试 验、 实 时 图 像 处 理、 气 象 分 析、 股 市 预 测、 人 工 智 能、 大 型 数 据 库 访 问 等 等。 客 户 机 可 以 是PC 机, 用 于 调 节 参 数、 控 制 进 程、 观 测 结 果 等, 其 效 果 如 同 置 身 于 超 级 计 算 机 上 直 接 运 行 程 序 一 样。 ---- 从 商 业 上 看, 超 级 计 算 机 可 以 向 更 多 的 用 户 提 供 商 业 服 务, 如 向 远 程 用 户 提 供 模 拟 试 验, 而PC 用 户 既 能 享 受PC 的 廉 价 方 便, 又 可 以 享 受 到Java RMI 带 来 的 原 来 不 可 想 象 的 超 级 计 算 的 威 力。 ---- 由 于 源 程 序 较 长, 故 发 表 在 本 报 的 WWW 站 点 上, 地 址 是:http: / /www.javaworld.com.cn /98 /jprogram.htm。 欢 迎 访 问! 中国计算机世界出版服务公司版权所有 用 微 机 作 传 真 和 数 据 通 信 河 南 南 阳 邮 电 局(473000) 张 菲 用 微 机 在 电 话 线 上 作 传 真 和 异 步 数 据 通 信, 是 微 机 用 于 通 信 领 域 最 简 单、 最 常 用 的 例 子。 它 们 都 需 要 相 应 的 软 硬 件 支 持。 软 件 方 面, 传 真 需 要 传 真 软 件, 而 数 据 通 信 只 要 有 一 般 的 异 步 通 信 软 件( 或 终 端 仿 真 程 序) 即 可; 它 们 都 占 用 微 机 的 一 个 串 行 通 信 口, 且 要 有 一 个Modem( 传 真 还 要 求 调 制 解 调 器 支 持 传 真 功 能)。 这 个Modem 必 须 设 置 成 异 步 拨 号 方 式, 而 不 能 是 同 步 或 专 线 方 式。 本 文 旨 在 介 绍 如 何 方 便 地 在 电 话 线 进 行 传 真 和 异 步 数 据 通 信 的 方 法。 Windows3.11 for Workgroups、Windows95 及 其 它 一 些 专 门 的 传 真 软 件 如Delrina Winfax, 都 提 供 了 用 微 机 收 发 传 真 的 功 能。 当 正 确 设 置 了 这 些 功 能 后, 用 户 均 可 以 在 这 些 软 件 下 传 真, 或 把 串 口 作 为“ 打 印 机” 来 发 传 真; 并 且 可 以 方 便 地 接 收 传 真。 下 面 分 别 说 明 它 们 的 使 用 方 法: 使 用Windows3.11 for Workgroups 收 发 传 真Windows3.11 for Workgroups 是 用 于 局 域 网 的 增 强 型Windows3.1, 单 机 同 样 也 可 以 使 用。 内 置 有 名 为Microsoft At Work PC Fax v1.0 的 传 真 软 件, 如 果 用 户 是 在 网 络 上, 则 大 家 可 以1 共 用 一 个Modem 对 外 收 发 传 真。 设 置: 1.Modem 必 须 是 一 级(Class 1) 或 二 级(Class 2) 或 通 信 应 用 规 范(Communication Applicatio n Specification) 的Modem。 如 果 是CAS Modem, 应 安 装 其 随 机 的 驱 动 程 序; 否 则 由PC Fax 驱 动, 只 需 把Modem 设 置 为 异 步 拨 号 方 式。 然 后 通 过RS-232 电 缆 接 在 一 个 空 闲 的 串 行 口 上, 开 启Modem 的 电 源。 2. 确 信 没 有 别 的 通 信 软 件 占 用 所 接 的 串 口, 打 开Control Panel 窗 口 中 的Fax 图 标。 如 果 用 户 还 没 有 用 过Mail, 会 出 现Mail and Fax 和Fax Only 供 选 择。 根 据 需 要 选 择 后 出 现Fax Modems 窗 口, 在 此 窗 口 里 选 择Add... 以 打 开Add Fax Modems 窗 口 选 择Modem 类 型。 可 供 选 择 的Modem 类 型 有 连 接 在 各 空 闲 串 口 上 的Fax Modem、CAS Modem 和 网 络 共 享 型Modem。 3. 选 择Modem 类 型( 非 网 络 共 享 型) 后, 系 统 将 对 所 置Modem 进 行 检 测, 成 功 后 出 现 窗 口 要 求 输 入 用 户 自 己 的 传 真 电 话 号 码( 包 括 国 家 代 码 和 地 区 代 码, 我 国 的 代 码 为86)。 收 发 传 真 时 这 个 电 话 号 码 会 在 对 方 传 真 机 的 液 晶 屏 上 显 示 出 来。 4. 按 下OK 按 钮 返 回 到Fax Modems 窗 口, 选 择Setup... 对Modem 的 应 答 方 式、 声 音、 拨 号 进 行 设 置, 最 好 将Modem 的 拨 号 设 置 为 盲 拨(Blind Dialing, 即 不 管 线 路 上 有 无 拨 号 音 都 拨 号, 设 为 盲 拨 的 原 因 在 稍 后 叙 述)。 用 户 以 后 还 可 以 修 改。 5. 由 于 传 真 是 在Mail 下 使 用, 所 以 在Fax Modems 窗 口 下 点 击OK 后 会 调 出Mail 窗 口, 由 用 户 进 行 必 要 的 设 置, 如 信 箱 的 登 录、 信 箱 文 件 等。 设 置 成 功 后 会 自 动 在Printers 增 加 名 为Microsoft At Work Fax on COMx: 的 打 印 机, 这 是 为 了 能 在 文 字 处 理 软 件(for Windows) 下 用Print 命 令 发 送 传 真。 由 于 某 种 原 因 或 用 户 日 后 不 慎 删 除 了 它, 安 装 的 打 印 机 栏 里 没 有Microsof At Work Fax on COMx:, 那 么 就 须 点 击Add>> 按 钮 后 在 打 印 机 列 表 里 选 择Install Unlisted or Updated Printer 并 点 击Install... 按 钮 添 加。Windows 出 现Install Driver 窗 口, 指 定Fax 驱 动 文 件 所 在 的 路 径 和 文 件 名(Windows 目 录 下 的SYSTEM/EFAXDRV.DRV), 按OK 后 没 有 安 装 打 印 机, 或 者 比 所 设 打 印 机 更 常 用, 应 把Fax 设 为 默 认 打 印 机。 PC Fax 的 使 用: 用 户 可 以 在Mail 下 使 用Fax 功 能, 也 可 以 在 字 处 理 软 件 下 使 用Fax 发 送 传 真; 至 于 传 真 的 接 收, 必 须 是 在Mail 运 行 时 才 能 做 到, 同 时Modem 必 须 打 开 电 源, 并 与 微 机 串 口、 电 话 线 可 靠 地 连 接 着; 如 果 是 内 置Fax/Modem 卡, 则 只 需 连 好 电 话 线。 为 方 便 起 见, 应 在Modem 的PHONE 口 接 上 电 话 机, 这 样 即 使Modem 电 源 没 有 打 开 也 可 以 打 电 话。 在Mail 下 发 送 传 真: 在Network 群 组 中 点 击Mail 图 标 打 开Mail 窗 口,Mail 将 会 自 动 检 测Modem, 并 调 出Microsoft At Work PC Fax 监 听 电 话 线 和 显 示 当 前 状 态。 在Mail 窗 口 的 工 具 栏 上 点 击Compose 按 钮( 或 者 选 择Mail →Compose Note), 出 现Send Note 窗 口。 在To 文 字 栏 中 键 入 接 收 者 的 名 字( 或 其 前 几 个 字 符, 由Mail 自 动 补 足), 也 可 从 点 击Send Note 窗 口 中 的Address 按 钮 选 择 接 收 者, 接 收 者 多 于 一 个 时, 之 间 用 分 号 隔 开( 注 意 接 收 者 必 须 登 记 在 地 址 簿 中); 如 果 需 要, 在Subject 文 字 栏 中 键 入 传 真 的 主 题, 在Cc( 抄 送) 文 字 栏 中 键 入 抄 送 者 名 字, 方 法 与To 文 字 栏 的 一 样; 在 编 辑 区 键 入 想 发 送 的 信 息, 如 果 需 要 发 送 某 个( 些) 纸 面 文 件, 可 点 击Send Note 窗 口 中 的Attach 按 钮 来 指 定。 设 置 完 毕 后, 点 击Send Note 窗 口 中 的Send 按 钮。PC Fax 将 把 信 息 转 换 成 传 真 格 式, 而 后 拨 接 收 者 的 电 话 号 码, 把 传 真 发 送 出 去。Inbox 窗 口 实 际 上 有 三 个 目 录, 窗 口 名 称 取 决 于 当 前 目 录 名:Inbox 存 放 收 到 的 传 真;Sent mail 存 放 已 发 传 真 的 备 份;Wastebasket 存 放 从 上 述 两 个 目 录 和Outbox 里 删 除 的 传 真 记 录( 废 纸 篓)。Outbox 内 保 持 要 发 送 的 传 真, 直 至 被 发 送 出 去; 发 送 出 去 后, 记 录 将 移 到Inbox 的Sent mail 内。 要 发 送Outbox 或 者Inbox 内 的 传 真, 可 选 中 后 点 击Forward 按 钮, 这 时 会 调 出FW 窗 口, 形 式 与Send Note 窗 口 类 似。 · 在 字 处 理 软 件 下 使 用PC Fax 发 送 传 真 打 开 要 发 送 的 文 件, 在“ 文 件” 菜 单 下 选 择 打 印 命 令, 把Fax Modem 指 定 为 要 输 出 的 打 印 机, 点 击OK 按 钮。Windows 会 调 出Mail, 接 下 来 的 设 置 与“ 在Mail 下 发 送 传 真” 一 样。 · 传 真 的 接 收 用 户 可 以 将PC Fax 设 置 为 自 动 应 答 方 式, 从 而 将 呼 到 自 己 电 话 线 上 的 呼 叫 都 当 作 要 收 的 传 真。 但 更 常 用 的 是 人 工 应 答, 即 用 户 在 接 电 话 后 确 认 对 方 要 发 传 真 时 才 让PC Fax 应 答。 这 可 以 在Mail 为 人 工 应 答,Off 则 不 应 答。 设 置 成 人 工 应 答 后, 在 用 户 拿 起 电 话( 接 在FaxModem 的PHONE 口 上) 得 知 对 方 要 发 传 真, 就 选 择FAX 菜 单Answer Now! 命 令, 或 选 择 振 铃 时 屏 幕 出 现 的 接 受 询 问 窗 中 的Yes 按 钮。PC Fax 就 会 使Modem 发 出 接 收 信 号, 准 备 接 收 传 真。 传 真 收 到 后, 记 录 会 显 示 在Inbox 中, 用 户 可 以 打 开 阅 读。 · 传 真 的 阅 读 在Mail 窗 口 双 击 传 真 信 息 条 来 读 取 接 收 到 的 或 发 送 的 传 真 信 息。 如 果 用 户 在Mail 窗 口FAX →Options... →Message Format 选 择 的 是Email if available, 则 传 真 不 一 定 是 以 传 真 图 像 格 式 收 发 的, 可 能 保 留 了 原 字 处 理 软 件 生 成 的 格 式, 这 些 文 件 会 以 字 处 理 软 件 图 标 的 形 式 显 示 出 来, 用 户 可 以 双 击 图 标 来 调 出 相 应 的 字 处 理 软 件( 如 果 硬 盘 上 有 此 字 处 理 软 件 的 话), 从 而 阅 读 这 些 文 件 的 内 容; 否 则 调 出Fax Viewer 应 用 程 序(Windows 目 录 下 的FAXVIEW.EXE)。PC Fax 是 根 据 纸 面 文 件 的 扩 展 名 来 决 定 调 用 哪 一 个 字 处 理 软 件 的, 而Fax Viewer 用 于 阅 读 传 真 格 式 文 件( 后 缀 是.DCX), 这 种 文 件 不 需 收 方 拥 有 与 发 方 相 同 的 字 处 理 软 件, 每 页 约 占80KB 的 磁 盘 空 间。 而 在Fax Viewer 下 单 独 保 存.DCX 文 件 的 一 页, 其 文 件 名 后 缀 是.PCX。 · 在 网 络 上 共 享 一 个Fax Modem 如 果 网 络 共 享 的Modem 接 在 你 的 微 机 上 你 就 须 对Modem 进 行 设 置; 并 且 你 会 收 到 给 你 和 网 络 上 其 他 人 的 传 真, 因 而 你 还 须 把 后 者 转 发 到 它 们 的 接 收 者 那 里。 在 前 述 的Fax Modems 窗 口 里 选 择 并 设 置 了Modem 后, 点 击Share... 按 钮( 此 按 钮 在 你 的 计 算 机 设 置 了 文 件 共 享 后 才 有 效)。 出 现Share Local Fax Modem 对 话 窗, 可 以 设 置Fax Modem 的 共 享 目 录, 默 认 为Windows 下 的MSFAX 目 录( 新 建)。 点 击Create Directory( 如 果 设 定 目 录 不 存 在) 或create Share...( 如 果 设 定 目 录 还 未 共 享)。 设 置 完 毕 后 返 回 直 至 关 闭Fax Modem 窗 口。 若 想 停 止 共 享Fax Modem, 只 要 在Fax Modems 窗 口 里 点 击Stop Sharing 按 钮 即 可。 要 转 发Fax, 首 先 需 打 开 它 以 便 弄 清 楚 接 收 者 是 谁。 在Mail 窗 口 里 双 击Fax 信 息 条。 如 果 传 真 是 从Mail 或 应 用 程 序 发 送 过 来 的,To 栏 会 显 示 接 收 者 的 名 字; 如 果 传 真 是 从 传 真 机 或 其 它 传 真 软 件 发 送 过 来 的, 双 击Fax 图 标 查 看 其 封 面 上 接 收 者 的 名 字。 点 击 工 具 栏 上 的Forward 按 钮, 在To 栏 键 入 接 收 者 的 名 字, 再 点 击 工 具 栏 上 的Send 按 钮 实 现 转 发。 PC Fax v1.0 收 发 传 真 的 一 般 操 作。 相 信 用 户 用 起 来 并 不 觉 得 方 便, 因 为 它 在 收 发 传 真 的 电 话 呼 叫 中 不 允 许 双 方 通 话, 那 么 能 否 象 传 真 机 那 样 在 双 方 通 话 后 收 发 传 真, 而 后 还 可 以 继 续 通 话 呢? 答 案 是 肯 定 的。 只 要 稍 改 变 一 下 操 作 就 行 了, 过 程 是 这 样 的: 电 话 拨 通 通 话 后 不 要 挂 机, 一 方 打 开Mail 窗 口 或 用 字 处 理 软 件 的Print 命 令 发 送 传 真; 而 另 一 方( 传 真 机 或Modem) 发 出 接 收 信 号。 这 时 发 送 方 所 设 接 收 者 的 电 话 号 码 已 经 失 去 了 本 来 的 作 用, 仅 仅 是 为 了 让Modem 摘 机, 从 而 收 到 双 方 的 接 收 信 号, 以 便 上 线 连 通。 由 于 这 时 电 话 线 上 没 有 拨 号 音, 故Modem 要 设 置 成 盲 拨, 这 就 是 先 前 为 什 么 建 议 把Modem 设 为 盲 拨 的 原 因。Modem 与 对 方 传 完 传 真 后, 会 自 动 下 线, 但 这 时 电 话 线 仍 然 没 断, 双 方 可 以 继 续 通 话。 这 个 方 法 同 样 适 用 于Windows95 和Delrina。 同 时, 由 于Windows3.11 发 送 传 真 的 时 间 不 太 确 定, 为 了 使 收 发 方 更 好 配 合, 收 方 最 好 在 发 方 给 出 发 送 信 号 后 再 发 出 接 收 信 号。 使 用Windows95 收 发 传 真 Windows95 不 使 用Mail 改 用Microsoft Exchange 管 理 传 真 功 能。 首 先 需 要 确 信 安 装 了Microsoft Fax( 在Start →Add/Remove Programs →Windows Setup 下 查 看, 没 有 安 装 则 在 此 安 装), 打 开Control Panel 窗 口 的Mail and Fax 图 标,Windows95 会 要 求 选 择 安 装Modem。 打 开Modems 图 标 对Modem 设 置。 安 装 成 功 后 会 在Printers 内 增 加 一 名 为Microsoft Fax 的 打 印 机, 并 在S tart →Programs →Accessories 下 自 动 建 立 与Games、Multimedia 等 并 列 的Fax 群 组。 要 想 在 开 机 后 就 监 视 线 路 状 态, 可 以 把Microsoft Exchange 放 入Startup 群 组 中。 Windows95 发 传 真 因 而 有 三 种 方 法: 从Microsoft Exchange、 字 处 理 软 件、Fax 群 组 均 可 发 传 真, 后 两 种 比 较 方 便。 根 据 提 示 用 户 可 以 很 快 掌 握 使 用 方 法。 需 要 注 意 的 是 在 发 本 地 传 真 时, 电 话 号 号 码 不 要 加 区 号。 FaxModem 的 盲 拨 和 应 答 方 式 均 可 在Start →Control Panel →Mail and Fax →Microsoft Fax Properties →Fax Modem Properties 中 设 置( 不 选 中Wait for dialtone before dialing 即 将Modem 设 为 盲 拨)。Microsoft Fax 运 行 时 在 任 务 栏 内 会 显 示 传 真 图 标。 在Modem 收 到 电 话 线 上 过 来 的 振 铃 信 号 时, 传 真 窗 口 自 动 打 开, 提 示 用 户 是 否 应 签( 接 收 传 真)。 用 户 可 以 在 通 话 后 再 打Yes, 以 便 接 收 传 真, 也 可 以 先 选No 关 闭 提 示 窗, 等 需 要 收 传 真 时 再 点 击 传 真 窗 口 的Answer Now 接 收。 Windows95 传 真 的 加 密 在Microsoft Exchange 窗 口 下Tools →Microsoft Fax Tools →Advanced Security... 中 设 置。 使 用Delrina Winfax 收 发 传 真 加 拿 大Delrina 公 司 的Winfax 是 专 业 的 传 真 软 件,3.0 版 随Modem 销 售, 同 时 在 一 张 磁 盘 上 还 提 供 了DOSFax 和 工 作 于Windows 和DOS 下 的 异 步 通 信 软 件COMit, 号 称4 合1(4in1);Winfax Pro4.0 版 共 有5 张3 1/2 磁 盘。 许 多 购 买Fax/Modem 随 赠 的 传 真 软 件 使 用 方 法 都 与 之 类 似。 与 前 两 个 传 真 应 用 程 序 相 比,Delrina Winfax 有 以 下 明 显 几 个 优 点: 1. 用 户 可 控 制 收 发 过 程 的 各 阶 段; 2. 有HOLD 功 能。 由 于 微 机 发 传 真 需 要 先 作 从 纸 面 文 件 到 传 真 格 式 的 转 换, 如 果 这 部 分 工 作 在 用 户 发 出 发 送 命 令 后 再 作, 就 不 能 很 好 地 与 对 端 配 合。Delrina Winfax 允 许 用 户 事 先 转 换, 而 后 发 出 发 送 命 令。 这 一 功 能 在 前 面 两 个 中 是 没 有 的; 3. 实 时 性 较 强。 前 两 个 传 真 应 用 程 序 在 用 户 发 出 发 送 命 令 后 并 不 立 即 发 送( 因 为 它 们 没 有 考 虑 到 用 户 需 要 通 话 后 再 发 送 的 场 合), 使 得 用 户 很 难 掌 握 发 送 的 确 切 时 间; 而 且 在 接 收 到 新 传 真 后 也 不 会 自 动 显 示、 打 印 出 来。 尤 其 是Windows3.11 for Workgroups, 在 接 收 到 传 真 后 还 不 能 立 即 在Inbox 里 给 出 记 录; 4. 用 户 界 面 更 加 友 好。 在 用 户 发 传 真 时, 如 果 由 于 某 个 原 因 发 送 失 败, 会 立 即 得 到 提 示, 而Windows3.11 for Workgroups 仅 仅 是 把 失 败 的 传 真 放 入Inbox 中, 给 出“ 不 能 发 送” 的 备 注 而 已; 收 到 传 真 后, 根 据 用 户 需 要 可 以 自 动 打 印 或 显 示 出 来, 等 等。 Message 格 式 设 为“Email of available”(Windows 3.11 for Workgroups) 或 者“Editable ,if possible”(Windos95); 如 果 纯 粹 使 用 传 真 进 行 数 据 通 信 而 不 打 算 与 传 真 机 通 信, 可 设 为“Email Format”(Windows 3.11 for Workgroups) 或 者“Editable Only”(Windows95)。 但 这 种 方 法 的 通 用 性 不 太 强。 其 中 一 般 的 异 步 通 信 软 件 或 终 端 仿 真 程 序 就 能 用 于 数 据 通 信、 而 且 用 起 来 更 方 便, 如Datastorm 的Procomm 及 其Plus、deltaComm 的Telix、Delrina 的COMit、Windows3.11 提 供 的Terminal、Windows95 的Hyper Terminal 均 可 实 现 数 据 通 信;Modem 也 只 要 是 可 以 传 数 据 的 异 步 拨 号Modem 即 可。 在 终 端 与 主 机 的 远 程 通 信、 拨 号 上 网 等 不 需 要 对 话 的 情 况 下, 操 作 是 很 简 单 的, 只 要Modem 是 异 步 拨 号Modem, 且 速 率 等 参 数 事 先 设 置 好 就 行 了。 我 们 这 里 要 讨 论 的 是 要 事 先 通 话 再 传 文 件 时 的 做 法。 人 们 通 常 是 这 么 作 的: 打 电 话 联 系, 作 好 通 信 准 备, 挂 机。 一 方Modem 设 为 自 动 应 答。 由Modem 拨 通 对 方, 由Modem 应 答, 上 线 连 通 后 按 事 先 约 定 收 发 文 件。 再 次 打 电 话 联 系, 如 果 刚 才 文 件 收 发 失 败, 重 新 约 定 作 好 准 备。 从 上 图 可 以 看 出, 这 些 步 骤 相 当 麻 烦, 为 作 一 次 数 据 通 信 就 需 要 连 续 打 三 次 电 话。 能 否 在 一 次 拨 通 过 程 完 成 这“ 三 步 曲” 呢? 传 真 通 信 给 了 我 们 有 益 的 启 示。 一 次 拨 通 过 程 中 既 要 通 话 又 要 完 成 数 据 通 信, 关 键 问 题 在 于 能 使Modem 既 能 接 管 电 话 线 传 数 据, 又 能 把 控 制 权 交 还 电 话 机。 为 此, 必 须 把 电 话 机 接 在Modem 的 电 话(PHONE) 插 口 上, 抑 制Modem 自 动 应 答( 否 则Modem 在 收 到 振 铃 信 号 后 就 控 制 了 电 话 线), 并 且 使Modem 可 以 接 受AT 命 令。 具 体 的 过 程 如 下 图 所 示: 人 工 拨 号 人 工 应 答 通 话, 作 好 通 信 准 备 和 约 定。 在 通 信 软 件 里 对Modem 发ATA 命 令 强 迫 其 进 入 联 机 应 答 模 式, 并 向 电 话 线 发 载 波 信 号。 在 通 信 软 件 里 对Modem 发ATO 命 令 使 其 摘 机 并 进 入 联 机 模 式。 Modem 训 练 上 线,CD( 载 波 检 测) 灯 亮 或 出 现CD 指 示。 同 时 通 信 软 件 里 显 示CONNECT....。 按 照 事 先 约 定 选 择 文 件 传 输 协 议 和 文 件 名, 发 送/ 接 收 文 件。 按 照 事 先 约 定 选 择 文 件 传 输 协 议 和 文 件 名, 接 收/ 发 送 文 件。 文 件 传 送 完 毕, 由 一 方 向Modem 发 出 拆 线 命 令+++、ATH, 通 信 软 件 里 显 示NO CARRIER。OH、CD 灯 灭。Modem 下 线, 把 控 制 权 交 还 电 话 机。 通 话。 挂 机 挂 机 说 明:1. 在 通 信 软 件( 或 异 步 终 端 仿 真 程 序) 下 键 入“AT”, 如 果 有“OK” 响 应, 表 明Modem 可 以 接 受AT 命 令。 不 然 首 先 看Modem 的SD 灯( 或 指 示) 在 对 键 盘 任 意 敲 入 字 符 时 是 否 会 闪 亮, 如 果 不 会, 则 端 口 设 置 错 误; 否 则Modem 没 有 设 置 为 可 以 接 受AT 命 令, 甚 至 根 本 就 没 有 设 置 为 异 步 方 式。 2. 抑 制Modem 自 动 应 答, 就 是 把 自 动 应 答 前 的 振 铃 次 数 设 置 为 零。 存 放 这 一 参 数 的 寄 存 器 通 常 就 是SO 寄 存 器, 在 通 信 软 件( 或 终 端 仿 真 程 序) 下 键 入“ATSO=O”, 就 抑 制 了Modem 的 自 动 应 答 功 能。 注 意 保 存 修 改 的 参 数。 抑 制 了 自 动 应 答 后 要 想 让Modem 应 答 呼 叫, 可 键 入ATA 命 令。 3. 对 于 提 供 有Voice/Data 转 换 天 关 的 外 置Modem, 如MultiTech、Hayes 等, 可 以 按 动V/D 开 关 来 代 表ATO 命 令( 在Modem 未 训 练 上 线 时), 或 代 替+++、ATH 命 令( 在 数 据 通 信 结 束 希 望 通 话 时, 这 时 也 可 以 关 掉Modem 强 迫 其 交 出 电 话 线 的 控 制 权)。 如 果 这 个V/D 开 关 还 有Answer 和Origin 俩 个 选 择, 则 扳 向Origin 意 义 与 前 相 同; 扳 向Answer 则 可 以 代 替ATA 命 令( 在Modem 未 训 练 上 线 时), 或 代 替+++、ATH 命 令( 在 数 据 通 信 结 束 希 望 通 话 时)。 4. 通 信 双 方 的 流 控(Flow Control)、 数 据 格 式(Data Format) 应 设 置 一 致。 流 控 一 般 有 三 种 选 择: 软 流 控(Xon/Xoff)、 硬 流 控(CTS/RTS) 以 及 无 流 控(None), 对 于 高 于2400b/s 的 较 高 速 通 信, 建 议 使 用 硬 流 控。 与 数 据 格 式 有 关 的 参 数 有: 数 据 位 的 比 特 长 度(5、6、7、8)、 校 验 位( 无 校 验None、 奇 校 验Odd、 偶 校 验Even、 恒 为“1”Mark、 恒 为“0”Space)、 停 止 位 长 度(1、1.5、2), 通 常 使 用 的 数 据 格 式 是N-8-1, 即 无 校 验 位、8 位 数 据 位、1 位 停 止 位。 为 防 止 乱 码, 最 好 也 把 串 口 速 率、 外 线 速 率 也 设 成 一 致。 5. 在 对Modem 操 作 时, 如 果 屏 幕 不 显 示 键 入 的 字 符 但 对 命 令 有 正 常 响 应, 说 明Modem 没 有 向 主 机 返 回 收 到 的 字 符, 这 时 可 以 打 开 通 信 软 件( 或 终 端 仿 真 程 序) 的 回 显(Local Echo) 功 能; 如 果 屏 幕 对 键 入 的 每 个 字 符 显 示 两 次, 表 明Modem 可 返 回 收 到 的 字 符, 这 时 可 以 关 掉Local Echo 功 能。 6. 在 收 发 文 件 时, 应 确 信 对 方 作 好 接 收(Download) 准 备 才 可 发 送(Upload), 以 免 收 到 的 文 件 不 完 整。 并 且 对 方 作 好 接 收 准 备 后 就 不 应 再 随 便 键 入 字 符 了, 否 则 这 些 字 符 也 会 被 看 作 是 文 件 的 一 部 分。 7. 文 件 传 输 协 议(FTP) 有 许 多 种, 但 异 步 通 信 软 件( 或 终 端 仿 真 程 序) 都 提 供 了ASC Ⅱ( 用 于 传 输 文 本 文 件) 和Kermit、XModem 或 其 改 进 版 如XModemCRC( 用 于 传 输 二 进 制 文 件)。 根 据 实 际 需 要 双 方 选 择 一 致 的FTP。 8. 如 果 在 接 收 文 本 文 件 时 出 现 总 在 某 一 行 快 速 显 示 收 到 内 容 的 现 象 时, 可 以 在 通 信 软 件 或( 终 端 仿 真 程 序) 里 设 置 在 每 一 接 收 进 来(Inbound) 的 回 车 符(CR) 后 再 加 上 一 个 换 行 符(LF); 如 果 出 现 键 入 的 字 符 或 收 到 的 字 符 总 在 屏 幕 最 下 一 行 显 示 的 现 象 时, 可 能 是 软 件 把 屏 幕 滚 动(Scroll) 功 能 关 掉 了, 用 户 可 以 打 开 这 个 功 能。 中国计算机世界出版服务公司版权所有