微电脑世界1999年第2期

Windows Sockets 浅析

 

  套 接 字(Socket) 起 初 来 源 于UNIX, 是 加 利 福 尼 亚 大 学Berkeley 分 校 开 发 的UNIX 操 作 系 统 下 的 网 络 通 信 接 口。 随 着UNIX 操 作 系 统 的 广 泛 使 用,Socket 亦 当 之 无 愧 的 成 为 了 最 流 行 的 网 络 通 信 程 序 接 口 之 一。90 年 代 初 期, 由Sun Microsystems,JSB.CO,FTP Software,Microdyne 和Microsoft 等 几 家 公 司 联 合 制 定 了 一 套Windows 下 套 接 字 编 程 的 规 范, 称 为Windows Sockets 规 范, 初 步 实 现 了Windows 下 的Sockets 接 口 程 序 的 标 准 化, 并 于1992 年 推 出 了Windows Sockets V1.0 版, 次 年 发 表 了 其2.0 版,IBM 发 行 的TCP/IP V2.1 for DOS 就 是 其 代 表, 它 还 提 供 了Windows Sockets 的 应 用 程 序 接 口(API)。 Microsoft 的Windows Sockets API 是Windows 下 的 网 络 应 用 程 序 接 口, 为 了 适 用 于Windows 下 的 消 息 机 制 和 异 步 的I/O 选 择 操 作,Windows Sockets API 在 功 能 上 扩 充 了 将 近20 个 函 数, 其 中 扩 充 的 部 分 均 冠 以 前 缀WSA(Windows Sockets Asynchronous), 如WSAStartup、WSAClean 等, 充 分 体 现 了Widnows 的 优 越 性。

  此 外,Windows Sockets API 有16 位 版 和32 位 版 两 种,16 位 版 是 单 进 程 的,32 位 版 则 提 供 了 多 线 程 下 的 安 全 保 护。

  本 文 将 浅 解Windows 下 的Sockets 编 程 的 机 理, 旨 在 抛 砖 引 玉。 一 并 说 明Windows Sockets 编 程 的 重 要 性 !

一、Windows Sockets 简 介

 

  套 接 字 是 网 络 通 信 的 基 本 构 件, 提 供 了 不 同 主 机 间 进 程 双 向 通 信 的 端 点, 如 同 电 话, 只 有 当 一 方 拨 通 另 一 方 的 电 话 时, 双 方 方 能 建 立 对 话, 而 套 接 字 正 好 比 双 方 的 电 话。 通 过Sockets 编 程, 程 序 可 以 跳 过 复 杂 的 网 络 底 层 协 议 和 结 构, 直 接 编 制 与 平 台 无 关 的 应 用 程 序。 随 着Internet 的 广 泛 应 用,Sockets 已 逐 渐 成 为 网 络 编 程 的 通 用 接 口。

  套 接 字 存 在 于 其 特 定 的 通 信 域( 即 地 址 族) 中, 只 有 隶 属 于 同 一 地 址 族 的 套 接 字 才 能 建 立 对 话,Windows Sockets V1.0 目 前 只 支 持 网 际 域(AF_INET), 所 有 使 用 网 际 协 议 簇 的 进 程 均 适 用 于 该 域。 一 般 情 况 下 除 非 通 信 协 议 支 持, 只 有 相 同 类 型 的 套 接 字 方 能 相 互 传 递 数 据,Windows Sockets V1.1 版 主 要 支 持 两 种 类 型 的 套 接 字: 流 式 套 接 字 和 数 据 报 套 接 字, 还 有 一 种 是 原 始 套 接 字, 但 为 保 证 网 络 应 用 程 序 的 兼 容 性, 一 般 不 鼓 励 使 用 原 始 套 接 字。

  流 式 套 接 字(SOCK_STREAM): 该 类 套 接 字 提 供 了 面 向 连 接 的、 可 靠 的、 数 据 无 错 并 且 无 重 复 的 数 据 发 送 服 务。 而 且 发 送 的 数 据 是 按 顺 序 接 收 的。 所 有 利 用 该 套 接 字 进 行 传 递 的 数 据 均 被 视 为 连 续 的 字 节 流 的 并 且 无 长 度 限 制。 这 对 数 据 的 稳 定 性、 正 确 性 和 发 送/ 接 受 顺 序 要 求 严 格 的 应 用 十 分 适 用,TCP 协 议 使 用 该 类 接 口。 但 其 对 线 路 的 占 用 率 相 对 提 高。 流 式 套 接 字 的 实 现 屡 见 不 鲜, 如 远 程 登 录(TELNET)、 文 件 传 输 协 议(FTP) 等 均 使 用 了 流 式 套 接 字。

  数 据 报 式 套 接 字(SOCK_DGRAM): 数 据 报 式 套 接 字 提 供 了 面 向 无 连 接 的 服 务 , 它 独 立 的 数 据 包 形 式 发 送 数 据( 数 据 包 长 度 不 能 大 于32KB), 不 提 供 正 确 性 检 查, 也 不 保 证 各 数 据 包 的 发 送 顺 序, 因 此, 可 能 出 现 数 据 的 重 发、 丢 失 等 现 象, 并 且 接 收 顺 序 由 具 体 路 由 决 定。 然 而, 数 据 报 的 实 现 对 网 络 线 路 占 用 率 较 低。NFS( 网 络 文 件 系 统) 即 是 采 用 此 类 套 接 字、 在TCP/IP 协 议 族 中,UDP(User Datagram Protocol) 使 用 该 类 接 口。

  原 始 套 接 字(SOCK_RAW): 该 套 接 字 一 般 不 会 出 现 在 高 级 网 络 接 口 的 实 现 中, 因 为 它 是 直 接 针 对 协 议 的 较 低 层( 如IP、TCP、UDP 等) 直 接 访 问 的。 常 用 于 检 验 新 的 协 议 实 现 或 访 问 现 有 服 务 中 配 置 的 新 设 备, 如 前 所 述, 一 般 不 提 倡 他 的 直 接 应 用。

  因 为Windows Sockets 主 要 是 面 向C/S 体 系 结 构 的, 即 客 户 向 服 务 器 发 出 请 求, 服 务 器 只 有 在 接 收 到 请 求 后 才 能 提 供 相 应 服 务。 双 方 在 建 立 对 话 前, 服 务 进 程 和 接 受 服 务 的 进 程( 客 户) 必 须 首 先 建 立 起 各 自 用 于 网 间 进 程 通 信 的 半 相 关, 即 一 个 三 元 组( 协 议, 本 地 地 址, 本 地 端 口), 但 只 有 双 方 独 立 的 半 相 关 还 不 能 建 立 起 沟 通。 一 个 完 整 的 网 络 通 信 进 程 必 须 通 过 由 两 个 独 立 进 程 组 成 的 一 个 完 整 的 全 相 关 唯 一 确 定 方 能 得 已 实 现, 而 且, 只 有 两 个 性 质 相 同 的 半 相 关 才 能 建 立 一 个 完 整 的 全 相 关 五 元 组 ─ ─( 协 议, 本 地 地 址, 本 地 端 口, 远 地 地 址, 远 地 端 口), 由 此 方 能 建 立 起 一 个 网 间 进 程 通 信 的 实 例。

  让 我 们 由C/S 模 式 的 主 动 请 求 方 式 来 解 释 用Windows Sockets 建 立 网 络 进 程 间 对 话 的 过 程。

  首 先 启 动 服 务 器 方, 以 提 供 相 应 服 务:

  (1) 打 开 一 个 通 信 通 道 并 通 知 网 络: 本 机 将 在 某 一 公 认 的 端 口 上 等 待 客 户 (Client) 请 求;

  (2) 服 务 器 进 入 阻 塞 等 待 状 态, 等 待 客 户 请 求 的 到 来;

  (3) 当 服 务 器 接 收 到 一 个 客 户 的 连 接 请 求 时, 激 活 一 个 新 的 进 程 用 于 处 理 客 户 请 求 并 建 立C/S 对 话, 服 务 完 成 后, 关 闭 此 新 进 程 与 客 户 的 通 信 链 路, 并 将 其 终 止;

  (4) 返 回 第(2) 步, 等 待 另 一 客 户 请 求;

  (5) 关 闭 服 务 器。

  客 户 端 进 程:

  (1) 指 定 想 与 之 建 立 连 接 的 服 务 器 相 应 服 务 的 保 留 端 口 号;

  (2) 向 服 务 器 发 送CONNECT 请 求 并 等 待 服 务 器 的 应 答;

  (3) 接 收 到 服 务 器 建 立 连 接 的 响 应 后 接 受 服 务 器 相 应 服 务;

  (4) 服 务 请 求 结 束 后 关 闭 通 信 通 道 并 终 止。

  由 此 可 见, 用Windows Sockets 建 立 的 面 向 连 接 的 无 重 复 套 接 字 系 统 的 过 程 实 现 图 解 如 下:

  流 式 套 接 字 首 先 由 客 户 与 正 在 某 一 端 口 监 听 的 服 务 器 建 立 起 连 接 后 方 能 进 行 数 据 传 送, 并 且 是 双 工 的。 与 此 不 同, 用 数 据 报 协 议 实 现 的 网 络 进 程 间 通 信 过 程 如 下:

  Windows Sockets 编 程 还 可 应 用 于 远 程 进 程 调 用(RPC), 它 使 得 用 户 进 程 可 调 用 远 端 的 进 程, 为 远 程 控 制 和 分 布 式 管 理 带 来 了 方 便。 在 对 等 网 络 中 应 用 也 极 其 广 泛, 如Windows 的 网 上 白 板(Chat) 和 红 心 大 战 均 是 通 过Windows Sockets 建 立 的 网 络 连 接 而 进 行 进 程 间 通 信 的。 现 今 的 许 多 网 络 游 戏 则 是Windows Sockets 的 直 接 利 用。 可 以 说Windows Sockets 是 网 络 游 戏

二、Windows Sockets 编 程 初 探

 

  1、Microsoft Visual Basic 实 现

  Microsoft Visual Basic 提 供 了 用 于Windows Sockets 编 程 的 可 用 控 件--Winsock 控 件。 该 控 件 为 用 户 提 供 了 访 问TCP 和UDP 网 络 的 极 其 方 便 的 途 径。 并 且 适 用 于Microsoft Access、Visual Basic、Visual C++ 和Visual FoxPro 等 多 种 可 视 化 环 境。 通 过Winsock 控 件 编 制C/S 程 序, 程 序 员 无 须 了 解TCP 或 低 级Winsock APIs 调 用 实 现 的 细 节, 如 用 户 无 须 考 虑 网 络 字 节 顺 序 与 本 机 字 接 顺 序 便 可 直 接 进 行 数 据 的 传 送。 用 该 控 件 实 现 网 间 进 程 通 信 极 其 方 便。

  在TCP 应 用 中, 为 了 建 立 一 个 网 络 连 接 实 例(Instance) 的 服 务 器 端, 只 需 设 置 本 地 服 务 断 口 号, 然 后 服 务 器 调 用 方 法Listen 进 入 阻 塞 状 态 等 待 来 自 客 户 的 连 接 请 求。 与 此 对 应 的 客 户 端 不 但 要 将Winsock 的 属 性RemoteHost 置 为 服 务 器 的 名 称(IP 地 址 或 网 络 代 号), 还 应 设 置 服 务 器 所 监 听 的 相 应 服 务 的 端 口 号(RemotePort), 如FTP 服 务 在21 号 端 口,HTTP 在81 号 端 口 等。 然 后 调 用 方 法Winsock.Connect 向 服 务 器 发 出 请 求。 服 务 器 接 收 到 客 户 请 求 时, 事 件ConnectionRequest 将 被 触 发。 如 服 务 器 愿 意 提 供 服 务 则 可 调 用Accept 方 法 接 受 连 接。

  一 旦 连 接 建 立, 两 端 均 可 使 用SendData 或GetData 进 行 数 据 的 发 送 或 接 收。 事 件DataArrival 将 在 另 一 端 数 据 准 备 就 绪 时 被 触 发。

  UDP 协 议 的 实 现 与TCP 不 同 的 是, 调 用Sockets 的 两 端 无 需 建 立 连 接 便 可 进 行 数 据 的 传 输。 因 此, 一 个UDP 应 用 可 以 同 时 担 任 服 务 器 或 客 户 的 角 色。

  以 下 程 序 代 码 为Visual Basic Windows Sockets 编 程 的 基 本 框 架。


     ' 服 务 器 方

     Private Sub Command1.Click()

        ' 设 置 本 地 服 务 端 口 号

        Winsock1.localport=2048

     

 	    ' 服 务 器 进 入 监 听 状 态

        Winsock1.listen 

 End Sub 

 

 Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)

    ' 收 到 客 户 连 接 请 求

    ' 检 查Socket 状 态

     If Winsock1.State <> sckClosed Then Winsock1.Close

     ' 接 受 客 户 请 求

     Winsock1.Accept requestID

     End Sub

     

     Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)

        ' 对 方 数 据 已 准 备 好

        ' 可 用GetData()/SendData() 接 收/ 发 送 数 据

        ' 处 理 客 户 数 据

        . . . . . .

     End Sub

     

     Private Sub Form_Unload(Cancel As Integer)

        Winsock1.Close

     End Sub

     

     ' 客 户 方

     Private Sub Command1.Click()

        ' 设 置 服 务 器 网 络 名

        Winsock1.RemoteHost=“193.168.1.40”

        

 		' 设 置 服 务 器 相 应 服 务 端 口 号

		Winsock1.RemotePort=2048

        

' 向 服 务 器 发 出 连 接 请 求

        Winsock1.Connect

 End Sub 

     

     Private Sub Winsock1_Connect()

        ' 服 务 器 响 应 连 接

        ' 可 以 进 行GetData()/SendData() 进 行 数 据 传 输

        . . . . . .

     End Sub 

     

     Private Sub Form1.Unload()

         Winsock1.Close

     End Sub 

  该 段 程 序 演 示 了 用Visual Basic 建 立TCP 连 接 的 基 本 过 程。 因 本 文 重 在 讲 解Sockets 编 程, 故 文 中 未 涉 及VB 自 己 封 装 的 故 障 处 理 函 数Winsock1.Erroe(), 读 者 可 自 行 编 制。 以 上 程 序 段 可 作 为 一 般TCP 应 用 的 基 本 框 架 加 以 扩 展 使 用。

  2、Microsoft Visual C++ 实 现

  MFC(Microsoft Foundmation Complierment) 提 供 了 两 种 类 定 义 以 实 现Sockets 应 用, 它 们 是:CAsynSockets 类 和CSockets 类。 此 两 种 类 的 区 别 为:CAsynSockets 封 装 了Windows Sockets API 函 数, 提 供 了 对Sockets 的 底 层 支 持, 直 接 应 用CAsynSockets 需 要 程 序 员 谙 习 网 络。 与 此 不 同 的 是CSockets 类 抽 象 化 了 这 些 底 层 细 节, 并 将 其 进 行 了 封 装。 此 外,CSockets 类 与CAchieve 类 结 合 应 用, 使 得 网 络 数 据 传 输 如 同 实 现 串 行 协 议 一 样 容 易。

  利 用MFC 建 立 网 络 通 信 的 过 程 如 下 所 示:

  (1) 构 造CSockets 对 象, 并 获 取 该 对 象 句 柄;

  (2) 在TCP 应 用 中, 客 户 端 应 使 用 缺 省 参 数 的Create 调 用, 而 对 于 服 务 器 对 象 来 说, 则 应 在 调 用Create 使 指 明 本 地 服 务 端 口 号;

  (3) 服 务 器 端 调 用CAsynSockets::Listen 进 入 监 听 状 态, 客 户 端 则 应 使 用CAsynSockets::Connect 向 服 务 器 发 出 请 求, 建 立 与 服 务 器 的 连 接。 服 务 器 在 接 收 到 客 户 请 求 后 由CAsynSockets::Accept 响 应 客 户 请 求;

  (4) 将 已 建 立 连 接 的CSockets 对 象 与CSocketsFile 对 象 相 关 连, 并 利 用CArchive 对 象 进 行 双 向 数 据 传 输( 如 同 文 件 读 写 操 作);

  (5) 网 络 通 信 进 程 结 束 后, 双 方 需 释 放CArchieve、CSockets 和CSocketsFile 对 象 的 占 用 资 源;

  其 大 体 实 现 过 程 与 前 述 的VB 实 现 类 同。 具 体 实 例 可 见Microsoft Visual C++ Samples 中 的chatsrv 与chater 程 序。

三、 综 述

 

  随 着Internet 的 逐 步 兴 起,Sockets 编 程 必 将 成 为 流 行 的 网 络 编 程 接 口 之 一。 也 许 您 会 发 问:ISO 的OSI 模 型 又 是 何 等 地 位 呢 ? 笔 者 的 观 点 是:ISO 的OSI 模 型 必 将 成 为 网 络 应 用 的 统 一 界 面,Sockets 接 口 的 广 泛 应 用 则 为OSI 模 型 开 拓 了 更 广 泛 的 应 用 前 景 !

 

back.gif (1185 字节)