通过E-mail共享Java对象 站点:爱心种子小博士 关键字:通过E-mail共享Java对象
|
通过E-mail共享Java对象 JDK1.1 的 新 功 能-- 序 列 化 接 口(Serializable interface), 简 化 了 对 象 持 久 化(Persistence) 的 实 现。 以 下 介 绍 如 何 通 过SMTP E-mail 将 对 象 传 送 给 另 一 个 用 户。
--------------------------------------------------------------------------------
摘 要: 一 些 应 用 程 序 需 要 以 一 种 非 实 时 的 方 式( 例 如 旅 行 指 南、 错 误 报 告(bug report)、 时 间 表(time sheet) 等) 和 其 余 用 户 共 享 对 象。 Java 语 言 开 发 工 具 包(JDK)1.1 版 提 供 了 一 个 重 要 的 功 能: java.io.Serializable 接 口。 该 技 术 能 让 你 知 道 如 何 序 列 化 一 个 对 象, 然 后 用e-mail 传 给 其 它 用 户。
对 象 持 久 化 和 用 户 间 对 象 共 享 是 许 多 商 业 解 决 方 案 的 基 础。 例 如,一个公 司 可 以 用 从 本 公 司 网 址 启 动 的Applet 来 完 成 一 个 时 间 表 的 制 作。 同 样 该公 司 也 可 以 提 供 象 具 有 开 支 报 告、 旅 行 指 南、 错 误 报 告(bug report) 等 功 能 的Applet。 在 这 些 情 况 下, 从Applet 的 使 用 者 获 得 的 数 据 需 要 和 负 责 薪 水、 付 款、旅 行 房 间 预 订 的 人 们 共 享。 执 行 这 些 职 能 的 人 们 可 能 分 布 在 不 同 的 城 市和 国 家, 可 能 工 作 在 不 同 的 时 区, 不 能 希 望 每 个 工 作 人 员 都 能 象 猫 头 鹰 一 样在 晚 上 工 作 以 填 写 这 样 的 表 格。 相 同 的 信 息 也 不 应 该 重 新 输 入。 因 此, 能 够存 储 并 且 把 这 些 相 关 对 象 传 送 到 商 业 应 用 中 是 这 些applet 有 别 于 其 它applet 的 优 势。
目 前 已 经 有 许 多 方 法 能 实 现 对 象 的 持 久 化, 例 如 使 用 对 象 数 据 库 和 磁盘 文 件。 同 样 的 也 有 许 多 办 法 可 以 共 享 对 象, 例 如 将 数 据 写 入 一 个 套 接 字, 或 者 实 现 一 个 符 合CORBA, SOM 的 模 型。 以 上 这 几 种 方 案 均 有 自 己 的 优 点, 当 你 设 计 你 的 商 业 解 决 方 案 时, 需 要 认 真 地 考 虑 这 些 方 案。 但 是, 还 有 一 种 开 销 不 大 但 可 靠 的 方 法, 它 使 用Internet 和Intranet 用 户 能 够 获 取 的 技 术 服 务 在 世 界 范 围 传 送 对 象 的 拷 贝。 它 就 是 简 单 邮 件 传 输 协 议, SMTP。
用E-mail 发 送Java 对 象 存 储 和 保 存 对 象 的 一 个 简 单 方 法 是 将 对 象 序 列 化 而 后 用E-mail 将 它 发 送 给 别 的 用 户。 这 种 方 法 有 以 下 优 点:
发 送 的 计 算 机 或NC( 网 络 计 算 机) 无 需 硬 盘 空 间
使 用 现 有 的 系 统 传 送、 排 队、 发 送 对 象
允 许 用 户 使 用 最 喜 欢 的 邮 件 客 户 程 序 来 接 受 邮 件
提 供 简 单 的 机 制 将 同 一 对 象 的 拷 贝 分 发 给 许 多 人 这 种 方 法 也 有 不 足 之 处:
邮 件 的 传 送 可 能 因 为E-mail 主 机 的 关 机 而 被 较 长 时 间 地 延 迟。 所 有 的 主 机 都 可 能 出 现 这 种 情 况, E-mail 服 务 器 的 错 误 恢 复 优 先 级 通 常 比 数 据 库 服 务 器 低。
邮 件 的 传 送 不 能 得 到 保 证-- 在 你 的E-mail 服 务 器 通 知 你 邮 件 没 有 发 出 时, 你 不 得 不 重 新 发 送 邮 件。
E-mail 服 务 器 和POP 客 户 程 序 的 功 能 不 足 以 处 理 大 量 交 易 信 息。 这 些 不 足 和 你 使 用 的 应 用 程 序 有 关。 对 于 很 多 商 业 解 决 方 案, 这 些 不 足 并 不 重 要。 作 为 一 个 设 计 人 员, 你 工 作 的 一 部 分 就 是 在 全 面 考 虑 价 格、 性 能 和 需 求 的 情 况 下 确 定 系 统 的 最 佳 整 体 结 构。
使 用Java 传 送 对 象 的 四 个 步 骤:
Applet 必 须 依 次 以 下 面 所 列 出 的 四 个 步 骤 传 送Java 对 象:
序 列 化 有 关 对 象
发 送 时 选 择Base64 编 码 方 式 对 序 列 化 对 象 编 码(RFC 1521)
与 一 个SMTP 服 务 器 连 接
将 该 对 象 传 送 到 这 个SMTP 服 务 器 下 面 将 介 绍 如 何 用E-mail 发 送 一 个 假 设 的" 臭 虫" 报 告 到 公 司 的 质 量 保 证 部 门。
将 对 象 序 列 化 JDK1.1 提 供 的 一 个 奇 妙 的 机 制, java.io.Serializable 接 口, 能 够 序 列 化 并 且 重 建 对 象。 这 个 接 口 能 使 用 存 储 对 象(writeObject()) 和 恢 复 对 象(readObject()) 方 法 函 数。 在 很 多 情 况 下, 使 用 这 个 接 口 很 方 便, 只 需 实 现 并 且 调 用 这 两 个 方 法 函 数。
以 下 的 代 码 定 义 了 一 个 简 单 的BugReport 对 象, 它 实 现 了 最 简 单 的 序 列化接 口。
1 import java.Io.*; 2 public class BugReport implements Serializable { 3 private Float m_SoftwareVersion; // version number from Help.About, e.g. "1.0" 4 private String m_ErrorDescription; // Description of error 5 private int m_Severity; // 1=System unusable - 5=Minor Aesthetic defect
6 public BugReport (Float SoftwareVersion, String ErrorDescription, int Severity) { 7 m_SoftwareVersion = SoftwareVersion; 8 m_ErrorDesctiption = ErrorDescription; 9 m_Severity = Severity; 10 }
11 public BugReport () {} // for reconstituting serialized objects
12 public void save (OutputStream os) 13 throws IOException { 14 try { 15 ObjectOutputStream o = new ObjectOutputStream(os); 16 o.writeObject(this); 17 o.flush(); 18 } 19 catch (IOException e) {throw e;} 20 }
21 public BugReport restore (InputStream is) 22 throws IOException, ClassNotFoundException { 23 BugReport RestoredBugReport = null; 24 try { 25 ObjectInputStream o = new ObjectInputStream(is); 26 RestoredBugReport = (BugReport)o.readObject(); 27 } 28 catch (IOException e) {throw e;} 29 catch (ClassNotFoundException e) {throw e;} 30 return RestoredBugReport; 31 } 32 }
1 使 用import 语 句 引 入I/O 包, 包 括 序 列 化 接 口。
2-5 定 义 类 中 的 成 员 变 量, 并 指 出 该 类 实 现 了 序 列 化 接 口。
6-10 提 供 一 个 简 单 的 构 造 函 数
11 一 个 空 的 构 造 函 数。 这 个 构 造 函 数 在 重 建 序 列 化 对 象 时 使 用。 见 以 下 的 例 子。
12-20 定 义 一 个 方 法 函 数, 它 把 对 象 写 入 一 个 已 经 打 开 了 的ObjectOutputStream。 这 个 方 法 函 数 首 先 创 建 一 个 ObjectOutputStream 对 象, 然 后 调 用writeObject 方 法 函 数, 最 后 在 函 数 返 回 前 显 式 清 空 输 出 缓 冲 区。
21-30 定 义 一 个 方 法 函 数, 它 从 一 个 打 开 了 的InputStream 中 读 入 一 个BugReport 对 象。 注 意, 如 果 输 入 流 中 下 一 个 对 象 和 正 在 读 入 对 象 的 类 型 不 一 致 时, readObject() 将 会 抛 出 一 个 异 常。
使 用BugReport 对 象 相 当 简 单。 譬 如 我 们 想 要 创 建 一 个 新 的BugReport 对 象 并 且 把 它 存 入 一 个 文 件, 我 们 会 用 到 以 下 代 码:
1 import java.io.*; . . 2 BugReport bug = new BugReport(1.0, "Crashes when spell checker invoked", 2); 3 FileOUtputStream os = new FileOutputStream("MyBug.test"); 4 bug.save(os);
很 简 单, 对 吗? 当 然, 一 旦 对 象 已 经 被 序 列 化, 没 有 人 能 阻 止 你 继 续 操 纵对 象 的 状 态。 上 一 个 例 子 中 包 涵 了 一 个 在 被 写 入 磁 盘 时 已 经 存 在 对 象 的 拷 贝。 因 此 你 必 须 要 十 分 谨 慎, 以 防 在 对 对 象 做 出 所 有 的 修 改 之 后 没 有 序 列 化 对 象, 从 而 丢 失 了 对 象 的 状 态 修 改 信 息。
以 下 是 怎 样 恢 复 一 个 对 象 的 拷 贝:
1 import java.io.* . . 2 FileInputStream fis = new FileInputStream("MyBug.test"); 3 BugReport bug = new BugReport().restore(fis);
这 更 简 单! 是 不 是Java 的 功 能 越 来 越 强 大 了?
现 在 我 们 修 改 第 二 个 例 子 的 第3 行, 使 对 象 被 写 入 一 个 字 节 数 组 而 不 是 一 个 文 件:
1 import java.io.* . . 2 BugReport bug = new BugReport(1.0, "Crashes when spell checker invoked", 2); 3 字 节ArrayOutputStream os = new 字 节ArrayOutputStream(); 4 bug.save(os);
好 了, 我 们 已 经 构 造 了 一 个 对 象, 并 且 学 会 把 它 序 列 化 后 放 入 一 个 字 节OutputStream。 然 后, 我 们 将 把 这 个 字 节OutputStream 转 化 为 一 个Base64 编 码 的 字 符 串。
. Base64 编 码 目 前 的Internet E-mail 标 准-- 简 单 邮 件 传 递 协 议(SMTP) 在RFC 821 中 宣 布。 对 于 我 们 来 说, RFC 821 对 邮 件 的 内 容 规 定 了 两 条 重 要 但 不 难 实 现 的 限 制。
1. 邮 件 的 内 容 必 须 全 部 为7- 比 特 的 美 国ASCII 码。
2. 每 一 行 的 长 度 不 能 超 过1000 的 字 符。
因 此 为 了 通 过SMTP 用E-mail 进 行 传 送, 内 存 的 序 列 化 对 象 必 须 转 化 为 和 以 上 相 容 的 格 式。
RFC 1521 提 供 了 一 个 可 行 的 方 案。 它 定 义 了 邮 件 的 内 容 部 分, 使 之 能 包 涵 多 种 形 式 的 数 据。 这 种 标 准 就 是 目 前 众 所 周 知 的MIME。
按 照RFC 1521 编 码 过 程 为: 输 入 是24 个 比 特, 输 出 是4 个 字 节。 24 个 比 特 输 入 组 从 左 至 右 由3 个8 比 特 的 输 入 组 形 成。 这24 个 比 特 被 看 成4 个 连 续 的6 比 特 组, 而 每 个6 比 特 输 入 组 被 翻 译 为Base64 码 表 中 的 一 个 数 字。
这 意 味 着 如 果 我 们 有 下 面 的3 个 字 节 的 输 入 -- xC, xF3, xFF -- 它 将 会 被 转 化 为 如 下 的Base64 的 编 码: x3, xF, xF, x3F。
图 Base64 编 码 实 例
Base64 编 码 似 乎 有 点 神 秘, 但 实 现 它 的 代 码 却 非 常 简 单, 在 下 面 的 程 序中 我 们 可 以 看 到 这 一 点。 在 这 个 例 子 中, 我 们 创 建 了 一 个 新 类, Codecs。 现 在, Codecs 有 两 个 方 法 函 数: 一 个 用 来 对 字 符 数 组 编 码, 一 个 用 来 对String 类 编 码。 对String 类 编 码 的 方 法 函 数 简 单 地 调 用String 类 的getBytes() 函 数, 然 后 对 返回的 结 果 字 符 数 组 进 行 编 码。 我 们 将 增 加 从Base6 解 码 至 原 先 格 式 的 方 法 函 数。
1 public class Codecs { 2 private Codecs() {} // do not instantiate this class
3 public final static String base64Encode(String strInput) { 4 if (strInput == null) return null; 5 byte byteData[] = new byte[strInput.length()]; 6 strInput.getBytes(0, strInput.length(), byteData, 0); 7 return new String(base64Encode(byteData), 0); 8 }
9 public final static byte[] base64Encode(byte[] byteData) { 10 if (byteData == null) return null; 11 int iSrcIdx; // index into source (byteData) 12 int iDestIdx; // index into destination (byteDest) 13 byte byteDest[] = new byte[((byteData.length+2)/3)*4];
14 for (iSrcIdx=0, iDestIdx=0; iSrcIdx >> 2) & 077); 16 byteDest[iDestIdx++] = (byte) ((byteData[iSrcIdx+1] >>> 4) & 017 | (byteData[iSrcIdx] << 4) & 077); 17 byteDest[iDestIdx++]="(byte)" ((byteData[iSrcIdx+2]>>> 6) & 003 | (byteData[iSrcIdx+1] << 2) & 077); 18 byteDest[iDestIdx++]="(byte)" (byteData[iSrcIdx+2] & 077); 19 } 20 if (iSrcIdx < byteData.length) { 21 byteDest[iDestIdx++]="(byte)" ((byteData[iSrcIdx]>>> 2) & 077); 22 if (iSrcIdx >> 4) & 017 | (byteData[iSrcIdx] << 4) & 077); 24 byteDest[iDestIdx++]="(byte)" ((byteData[iSrcIdx+1] << 2) & 077); 25 } 26 else 27 byteDest[iDestIdx++]="(byte)" ((byteData[iSrcIdx] << 4) & 077); 28 } 29 for (iSrcIdx="0;" iSrcIdx < iDestIdx; iSrcIdx++) { 30 if (byteDest[iSrcIdx] < 26) byteDest[iSrcIdx]="(byte)(byteDest[iSrcIdx]" + ´A´); 31 else if (byteDest[iSrcIdx] < 52) byteDest[iSrcIdx]="(byte)(byteDest[iSrcIdx]" + ´a´-26); 32 else if (byteDest[iSrcIdx] < 62) byteDest[iSrcIdx]="(byte)(byteDest[iSrcIdx]" + ´0´-52); 33 else if (byteDest[iSrcIdx] < 63) byteDest[iSrcIdx]="+" ; 34 else byteDest[iSrcIdx]="/" ; 35 } 36 for ( ; iSrcIdx < byteDest.length; iSrcIdx++) 37 byteDest[iSrcIdx]="=" ; 38 return byteDest; 39 } 40 } 1-2 定 义public 的Codecs 类 和 一 个 不 能 被 用 户 调 用 的 构 造 函 数。 通 常, 这 个 类
不 应 被 例 示。
3-8 定 义 一 个encodeBase64() 方 法 函 数。 它 的 参 数 类 型 是String 类 型, 返 回Base64 编 码 的String。 它 通 过 调 用String。getBytes() 并 将 结 果 数 组 传 送 至encodeBase64(byte[]) 来 完 成 函 数 的 功 能。
9-39 定 义 一 个encodeBase64() 方 法 函 数。 参 数 为 字 符 数 组, 返 回Base64 编 码 的 数 组 数 组。
10 如 果 参 数 值 为null, 退 出 方 法 函 数。
11-13 定 义 工 作 变 量, 其 中 字 节Dest 数 组 包 含 了 返 回 调 用 者 的 编 码。 注 意, 转 换 后 的 数 组 比 输 入 数 组 大 约 大 三 分 之 一。 这 是 因 为 每 个 三 字 节s 组 被 转 换 成 四 个 字 节。
14-19 循 环 遍 历 整 个 输 入 数 组, 每 次24 比 特, 把 这 三 个8 比 特 组 转 换 成 四 个两两 之 间 相 距 二 比 特 的6 比 特 组。 这 段 代 码 比 最 初 出 现 时 简 单。 仔 细 学 习, 看 看 和 前 面 的 例 子 有 什 么 不 同。
20-28 如 果 输 入 数 组 的 字 节s 数 目 不 是3 的 倍 数, 则 转 换 余 下 的1 或2 个 字 节。
29-35 把 所 得 的 编 码 数 据 作 为Base64 码 表 的 下 标。(Base64 码 表 在RFC 1521 中 说 明)
36-37 把 目 标 串 中 的 没 有 使 用 的 字 符 置 为´=´。
38 返 回 给 调 用 者 基 于Based64 的 编 码。
我 们 已 经 取 得 了 很 重 要 的 进 展。 到 目 前 为 止, 我 们 已 能 序 列 化 对 象 并 将 它 放 入 内 存, 把 它 转 化 为 基 于Base64 编 码, 目 的 是 使 用E-mail 工 具 将 它 发 给 目 标 用 户。 作 为 我 们 目 前 进 展 的 总 结, 下 面 有 一 个 代 码 片 断, 它 生 成 一 个BugReport 对 象 实 例, 把 它 序 列 化 并 放 入 内 存, 然 后 转 化 为Base64 编 码。
1 import java.io.*; 2 import Codecs.base64Encode; : 3 BugReport bug = new BugReport(1.0, "Crashes when spell checker invoked", 2); 4 字 节ArrayOutputStream os = new 字 节ArrayOutputStream(); 5 bug.save(os); 6 String strSerializedBug = os.toString(); 7 strSerializedBug = Codecs.base64Encode(strSerializedBug); . 和SMTP 服 务 器 连 接 如 果 你 想 发 一 封 邮 件, 必 须 通 过 以 下 五 个 步 骤:
1. 为SMTP 服 务 器 申 请 一 个 域 名
2. 建 立 一 个TCP/IP 的 会 话(session)
3. 在 服 务 器 上 登 录
4. 填 写 收 信 人 的 地 址
5. 撰 写 邮 件 的 内 容
下 面 分 别 就 这 些 步 骤 进 行 讨 论。
.. 为SMTP 服 务 器 申 请 一 个 域 名
正 如 你 发 送 普 通 信 件 一 样, 你 首 先 得 找 一 个 邮 局。 对 居 民 区 和 商 业 单 位 来 说 这 是 一 件 非 常 简 单 的 事, 因 为 邮 筒 就 在 门 口。 Internet 上 的 电 子 邮 件 也 同 样 简 单。
你 或 许 已 经 有 一 个Internet 的 电 子 邮 件 帐 号, 如 果 这 样, 你 的 邮 件 阅 读 工 具, 可 能 是 和WWW 浏 览 器 捆 绑 在 一 起 的 软 件, 或 者 是 单 独 的 软 件 如Eudora, 要 求 你 输 入 一 个 有 关SMTP 服 务 器 的 信 息。 它 就 是 你 所 使 用 的DNS 服 务 器 的 域 名。这 里 有 一 些Internet 服 务 提 供 商(ISP) 供 商 的SMTP 服 务 器 域 名:
你 的Internet 服 务 提 供 商 将 为 它 的SMTP 服 务 器 使 用 和 上 例 相 似 的 域 名。
.. 与 服 务 器 建 立 一 个TCP/IP 会 话
一 般SMTP 服 务 器 在25 号 端 口(port 25) 监 听 连 接 请 求。 因 此, 和 一 个SMTP 主机建 立 一 个TCP/IP 连 接 就 是 建 立 一 个 和25 号 端 口 连 接 的 套 接 字(socket)。 下 面 这 段Java 程 序 试 图 建 立 一 个 和 域 名 为"smtp.tjd.com" 的 主 机 的 连 接:
1 import java.net.*; 2 import java.io.*; 3 : 4 Socket socketSmtpServer = null; 5 DataOutputStream dos = null; 6 DataInputStream dis = null;
7 try { 8 socketSmtpServer = new Socket("smtp.tjd.com", 25); 9 dos = new DataOutputStream(socketSmtpServer.getOutputStream()); 10 dis = new DataInputStream (socketSmtpServer.getInputStream()); 11 } 12 catch (UnknownHostException e) {throw (e);} 13 catch (IOException e) {throw (e);}
这 段 代 码 在 建 立TCP/IP 连 接 的 同 时 创 建 一 个DataOutputStream 对 象 和 一 个DataInputStream 对 象, 我 们 以 后 将 会 使 用 它 们 从SMTP 服 务 器 发 送 和 接 收 数 据。
.. 在 服 务 器 上 登 录
和 在UNIX 系 统 或 者 数 据 库 系 统 上 登 录 不 同, 你 无 须 在 一 个SMTP 服 务 器 上真 正 地 登 录, 因 为 这 里 没 有 确 认/ 授 权 的 过 程, 根 本 不 需 要 真 正 登 录。 你 只 是简 单 地 让 服 务 器 能 识 别 你, 这 样 才 有 资 格 成 发 送 邮 件。 这 一 步 其 实 不 真 正 需 要, 但 是 不 能 忽 略 它。
当 你 第 一 次 和 服 务 器 连 接 时, 服 务 器 给 你 发 送 确 认 它 自 己 和 它 的SMTP 版 本 号 两 行 数 据。 我 们 不 关 心 这 些 数 据, 我 们 只 是 读 入 它 们 并 且 将 其 忽 略。在 我 们 读 入 这 些 数 据 后, 服 务 器 将 把 我 们 推 到" 司 机" 的 座 位 上 然 后 等 待 和 回 答 命 令。 下 面 是 用Java 语 言 实 现 的 登 录 过 程:
1 String strBuf; 2 String strMyName = "tomdaley"; 3 strBuf = dis.readLine(); 4 strBuf = dis.readLine(); 5 dos.writeBytes("HELO " + strMyName + "
"); 6 strBuf = dis.readLine(); 7 dos.writeBytes("RSET
"); 8 strBuf = dis.readLine();
HELO 命 令 让 服 务 器 识 别 你 的 身 份, RSET 命 令 重 置SMTP 服 务 器 的 状 态。 如 果 一 切 顺 利, RSET 命 令 不 是 必 须 的。 但 是 因 为 事 情 并 非 总 是 进 行 顺 利, 而RSET 是 一 个 发 送 和 执 行 起 来 很" 便 宜" 的 命 令, 因 此 首 先 执 行 这 条 命 令 是 一 个 很 好 的 方 法。
注 意 在 每 条write 字 节s() 语 句 后 的readLine() 语 句, SMTP 服 务 器 为 你 发 送 的 每 条 命 令 返 回 一 个 状 态 信 息。 状 态 信 息 以 一 个3 字 节 的 数 字 开 始, 它 被 用 来 判 断 命 令 执 行 成 功 与 否。 RFC 821 对 此 有 详 尽 的 解 释。
.. 写 明 收 信 人 的 地 址
下 一 步 我 们 准 备 填 写 收 信 人 的 地 址。 和 所 有 礼 貌 的 信 件 相 似, 我 们 应 该 提 供 给 邮 件 传 送 代 理 和 接 收 者 地 址 同 样 清 楚 的 回 信 地 址。 下 面Java 的 代 码 实 现 了 这 个 功 能:
1 dos.writeBytes("MAIL FROM:
"); 2 dis.readLine(); 3 dos.writeBytes("RCPT TO:
"); 4 dos.readLine();
.. 撰 写 邮 件 的 内 容
现 在 我 们 准 备 创 建 邮 件 最 有 趣 的 部 分-- 数 据 区 域。 数 据 区 域 包 括 两 个 子 区 域:
1. 邮 件 客 户 程 序 阅 读 的 头 部 信 息
2. MIME- 编 码 的 正 文 和 数 据
数 据 区 域 的 头 部 信 息 并 不 是 必 须 的, 但 在 你 使 用 收 信 客 户 程 序 看 信 时, 它 能 使 你 的 邮 件 看 起 来 更 美 观。 头 部 信 息 是 邮 件 内 容 的 一 个 概 括, 它 使 邮 件 更 容 易 管 理。
数 据 区 域 头 部 信 息 和 办 公 室 间 的 备 忘 录 的 开 头 相 似, 可 以 这 样 发 送:
1 dos.writeBytes ("DATAN"); 2 strBuf = dis.readLine(); 3 dos.writeBytes ("To: Tom Daley
"); 4 dos.writeBytes ("From: Tom Daley
"); 5 dos.writeBytes ("Subject: Bug Report
");
注 意, 我 们 在 发 送"DATA" 命 令 后 读 入 且 只 读 入 一 行。 当 你 发 送"DATA" 命 令 的 时 候, 服 务 器 可 能 回 送 下 面 形 式 的 消 息 作 为 应 答:"354 Enter mail, end with "." on a line by itself"。 这 意 味 着 如 果SMTP 服 务 器 没 有 看 到 信 件 的 结 尾, 不 会 通 过 套 接 字 发 送 任 何 数 据。
为 了 能 传 送 序 列 化 编 码 对 象, 我 们 把 它 封 闭 到 邮 件 内 容 的MIME 部 分。 MIME 部 分 最 开 始 是 纯 文 本, 用MIME 的 语 法 来 描 述, 就 是"Content-Type: text/plain。"。 在 文 本 部 分 我 们 将 发 送 若 干 指 令, 用 来 指 明 一 起 发 送 的 对 象 和 关 于 它 的 简 单 说 明。 下 面 的 代 码 实 现 了 这 种 功 能:
1 String strBoundary = "SimpleBoundary"; 2 String strInstructions = "Save the attached file and read it with BugNews.class."; 2 dos.writeBytes("Mime-Version 1.0
"); 3 dos.writeBytes("Content-Type: multipart/mixed; boundary="" + strBoundary + ""
"); 4 dos.writeBytes("--" + strBoundary + "
"); 5 dos.writeBytes("Content-Type: text/plain; charset="us-ascii"
"); 6 dos.writeBytes(strInstructions + "
");
现 在 我 们 该 做 费 了 这 么 多 的 口 舌 一 直 想 做 的 事 情, 将 序 列 化 的 对 象 附在SMTP 邮 件 内 容 上。 请 记 住, 邮 件 内 容 每 行 不 能 超 出1000 个 字 节。 对 于 有 多 个部 分 的MIME 则 有 更 多 的 限 制, 即 每 行 不 能 超 出74 个 字 节 的 二 进 制 编 码。 这 意 味 着 我 们 必 须 声 明 一 个string 对 象, 它 包 含 序 列 化 的, 基 于BASE64 编 码 对 象, 然 后 我 们 以 每 次74 个 字 节 的 方 式 将 这 个string 对 象 写 入SMTP 套 接 字。
1 dos.writeBytes("--" + strBoundary + "
"); 2 dos.writeBytes("Content-Type: application/octet-stream; name="BugReport.bug"
"); 3 dos.writeBytes("Content-Transfer-Encoding: base64
"); 4 dos.writeBytes("Content-Disposition: attachment; filename="BugReport.bug"
"); 5 dos.writeBytes("Content-Description: Bug Report from a customer
"); 6 int iLines = strObject.length() / 74; 7 for (i = 0; i 我们完成了!现在我们的错误报告(bug report)正延着全球SMTP邮件分发系统迂回前进,它将很快出现在 一些人的办公桌上。不过我敢打赌,他们收到错误报告时的心情不会和你解决如何发送它时的心情一样愉快 |
|
|
|