MFC网络编程-.doc
网络程序设计教材一、TCP/IP体系结构、特点及相关术语1、TCP/IP体系结构TCP/IP协议实际上就是在物理网上的一组完整的网络协议。其中TCP是提供传输层服务,而IP则是提供网络层服务。TCP/IP包括以下协议:(结构如图1.1)IP: 网间协议(Internet Protocol) 负责主机间数据的路由和网络上数据的存储。同时为ICMP,TCP,UDP提供分组发送服务。用户进程通常不需要涉及这一层。ARP: 地址解析协议(Address Resolution Protocol)此协议将网络地址映射到硬件地址。RARP: 反向地址解析协议(Reverse Address Resolution Protocol)此协议将硬件地址映射到网络地址ICMP: 网间报文控制协议(Internet Control Message Protocol)此协议处理信关和主机的差错和传送控制。TCP: 传送控制协议(Transmission Control Protocol)这是一种提供给用户进程的可靠的全双工字节流面向连接的协议。它要为用户进程提供虚电路服务,并为数据可靠传输建立检查。(注:大多数网络用户程序使用TCP)UDP: 用户数据报协议(User Datagram Protocol)这是提供给用户进程的无连接协议,用于传送数据而不执行正确性检查。FTP: 文件传输协议(File Transfer Protocol)允许用户以文件操作的方式(文件的增、删、改、查、传送等)与另一主机相互通信。SMTP: 简单邮件传送协议(Simple Mail Transfer Protocol)SMTP协议为系统之间传送电子邮件。TELNET:终端协议(Telnet Terminal Procotol)允许用户以虚终端方式访问远程主机HTTP: 超文本传输协议(Hypertext Transfer Procotol)TFTP: 简单文件传输协议(Trivial File Transfer Protocol)2、IP地址和子网掩码 要学习TCP/IP协议,首先要提到的是IP地址。每台主机的IP地址是一个32位的二进制数。每个IP地址被分割位两部分:前缀和后缀。前缀用来确定计算机从属的物理网络,后缀用来确定网络上单独的计算机。互联网上每一个物理网络都有一个唯一的值作为网络号,该网络号必须全球一致。1、IP地址分类:IP地址分位五类:A类、B类、C类、D类、E类其中A类、B类和C类为基本类D类用于多播E类属于保留类,现在不用。它们的格式如下(其中*代表网络号): A类:0* XXXXXXXX XXXXXXXX XXXXXXXX B类:10* * XXXXXXXX XXXXXXXX C类:110* * * XXXXXXXX D类:1110* XXXXXXXX XXXXXXXX XXXXXXXX E类:1111* XXXXXXXX XXXXXXXX XXXXXXXX 这样,A类地址的范围为:0.0.0.0-127.255.255.255 B类地址的范围为:128.0.0.0-191.255.255.255 C类地址的范围为:192.0.0.0-223.255.255.255 D类地址的范围为:224.0.0.0-239.255.255.255 E类地址的范围为:240.0.0.0-247.255.255.266 几个特殊IP地址 网络地址:IP地址中主机地址全为0的地址,如128.211.0.0。 广播地址:IP地址中主机地址全为1的地址,如128.211.255.255。 环回地址:127.0.0.1,主要用于测试。2、子网掩码: 现在的主机都要求支持子网掩码,不再把IP地址看成为由单纯的一个网络号和一个主机号组成,而是把主机号再分成一个子网号和一个主机号。例如一个B类地址(140.252),在剩下的16位中,8位用于子网号,8位用于主机号,这样就允许254个子网,每个子网就可以有254台主机。为了确定多少位用于子网号,多少位用于主机号,这就要用到子网掩码了。其中值为1的位留给网络号和子网号,为0的位留给主机号。3、TCP/IP特点TCP/IP协议的核心部分是传输层协议(TCP、UDP),网络层协议(IP)和物理接口层,这三层通常是在操作系统内核中实现。因此用户一般不涉及。编程时,编程界面有两种形式:一、是由内核心直接提供的系统调用;二、使用以库函数方式提供的各种函数。前者为核内实现,后者为核外实现。用户服务要通过核外的应用程序才能实现,所以要使用套接字(socket)来实现。图1.2是TCP/IP协议核心与应用程序关系图。二、专用术语1、套接字它是网络的基本构件。它是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连听进程。套接字存在通信区域(通信区域又称地址簇)中。套接字只与同一区域中的套接字交换数据(跨区域时,需要执行某和转换进程才能实现)。WINDOWS 中的套接字只支持一个域网际域。套接字具有类型。WINDOWS SOCKET 1.1 版本支持两种套接字:流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM) 2、WINDOWS SOCKETS 实现一个WINDOWS SOCKETS 实现是指实现了WINDOWS SOCKETS规范所描述的全部功能的一套软件。一般通过DLL文件来实现3、阻塞处理例程阻塞处理例程(blocking hook,阻塞钩子)是WINDOWS SOCKETS实现为了支持阻塞套接字函数调用而提供的一种机制。4、多址广播(multicast,多点传送或组播)是一种一对多的传输方式,传输发起者通过一次传输就将信息传送到一组接收者,与单点传送(unicast)和广播(Broadcast)相对应。1、客户机/服务器模式在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)。该模式的建立基于以下两点:1) 非对等作用;2) 通信完全是异步的。客户机/服务器模式在操作过程中采取的是主动请示方式:首先服务器方要先启动,并根据请示提供相应服务:(过程如下)1、打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。2、等待客户请求到达该端口。3、接收到重复服务请求,处理该请求并发送应答信号。4、返回第二步,等待另一客户请求5、关闭服务器。客户方:1、打开一通信通道,并连接到服务器所在主机的特定端口。2、向服务器发送服务请求报文,等待并接收应答;继续提出请求3、请求结束后关闭通信通道并终止。2、基本套接字为了更好说明套接字编程原理,给出几个基本的套接字,在以后的篇幅中会给出更详细的使用说明。1、创建套接字socket()功能:使用前创建一个新的套接字格式:SOCKET PASCAL FAR socket(int af,int type,int procotol);参数:af: 通信发生的区域type: 要建立的套接字类型procotol: 使用的特定协议2、指定本地地址bind()功能:将套接字地址与所创建的套接字号联系起来。格式:int PASCAL FAR bind(SOCKET s,const struct sockaddr FAR * name,int namelen);参数:s: 是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。其它:没有错误,bind()返回0,否则SOCKET_ERROR地址结构说明:struct sockaddr_inshort sin_family;/AF_INETu_short sin_port;/16位端口号,网络字节顺序struct in_addr sin_addr;/32位IP地址,网络字节顺序char sin_zero8;/保留3、建立套接字连接connect()和accept()功能:共同完成连接工作格式:int PASCAL FAR connect(SOCKET s,const struct sockaddr FAR * name,int namelen);SOCKET PASCAL FAR accept(SOCKET s,struct sockaddr FAR * name,int FAR * addrlen);参数:同上4、监听连接listen()功能:用于面向连接服务器,表明它愿意接收连接。格式:int PASCAL FAR listen(SOCKET s, int backlog);5、数据传输send()与recv()功能:数据的发送与接收格式:int PASCAL FAR send(SOCKET s,const char FAR * buf,int len,int flags);int PASCAL FAR recv(SOCKET s,const char FAR * buf,int len,int flags);参数:buf:指向存有传输数据的缓冲区的指针。 6、多路复用select()功能:用来检测一个或多个套接字状态。格式:int PASCAL FAR select(int nfds,fd_set FAR * readfds,fd_set FAR * writefds, fd_set FAR * exceptfds,const struct timeval FAR * timeout);参数:readfds:指向要做读检测的指针writefds:指向要做写检测的指针exceptfds:指向要检测是否出错的指针timeout:最大等待时间7、关闭套接字closesocket()功能:关闭套接字s格式:BOOL PASCAL FAR closesocket(SOCKET s);3、典型过程图2.1 面向连接的套接字的系统调用时序图2.2 无连接协议的套接字调用时序图面向连接的应用程序流程图对MFC封装 Windows 通讯 API的研究 一、 引 言 近 年 来, 利 用Internet 进 行 网 际 间 通 讯, 在WWW 浏 览、FTP、Gopher 这 些 常 规 服 务, 以 及 在 网 络 电 话、 多 媒 体 会 议 等 这 些 对 实 时 性 要 求 严 格 的 应 用 中 成 为 研 究 的 热 点, 而 且 已 经 是 必 需 的 了。Windows 环 境 下 进 行 通 讯 程 序 设 计 的 最 基 本 方 法 是 应 用Windows Sockets 实 现 进 程 间 的 通 讯, 为 此 微 软 提 供 了 大 量 基 于Windows Sockets 的 通 讯API, 如WinSock API、WinInet API 和ISAPI, 并 一 直 致 力 于 开 发 更 快、 更 容 易 的 通 讯API, 将 其 和MFC 集 成 在 一 起 以 使 通 讯 编 程 越 来 越 容 易。 MFC 是VC 编 程 环 境 最 重 要 的 组 成 部 分, 它 为 用 户 提 供 了 一 大 批 预 先 定 义 的 类 和 成 员 函 数, 封 装 了 大 量 的Windows API。 同 时VC 环 境 提 供 了 与MFC 对 象 和 代 码 一 起 工 作 的 专 用 工 具:AppStudio 源 程 序 编 辑 器、AppWizard 和Class Wizard。 应 用 MFC, 可 以 使Windows 程 序 员 用 较 少 的 时 间 和 精 力 开 发 出 复 杂 的 通 讯 应 用 程 序。 本 文 根 据 笔 者 自 己 在 开 发 实 时 网 络 音 频 工 具FreeTalk 过 程 中 的 一 些 经 验, 介 绍Windows 环 境 下 的 常 用API 和 封 装 它 们 的MFC 类, 重 点 介 绍 使 用MFC 的CAsyncsocket 和CSocket 类 编 写 网 络 通 讯 程 序 的 方 法, 这 两 个 类 封 装 了WinSock API, 并 使 他 们 更 容 易 使 用 和 更 适 应 于MFC 编 程 环 境。 二、Windows 环 境 下 的 通 讯API 和 相 应 的MFC 类 1. Windows Sockets(WinSock)API- Windows Sockets 定 义 了Windows 的 网 络 编 程 接 口, 它 基 于 加 利 福 尼 亚 大 学 伯 克 利 分 校 的 伯 克 利Unix Sockets。Windows Sockets 既 包 括BSD 风 格 的 例 程, 还 加 入 了Windows 的 扩 展 部 分, 例 如 用 于 消 息 驱 动 的 扩 展 函 数。Windows Sockets 可 以 运 行 在 许 多 网 络 协 议 之 上, 包 括TCP/IP、XNS、DECNet、IPX/SPX 等。 在Win32 环 境 下,Windows Sockets 提 供 线 程 安 全。 通 过 微 软 与 标 准 组 织 的 努 力, 为WinSock 定 义 了 应 用 程 序 设 计 接 口(WinSock API), 可 以 非 常 方 便 地 利 用 下 层 的 网 络 协 议( 如TCP/IP) 进 行 网 络 通 讯。 - 通 过 提 供 两 个 类CAsyncSocket 和CSocket,MFC 支 持 使 用WinSock API 通 讯 程 序 设 计。MFC 把 复 杂 的WinSock API 封 装 到 类 里, 这 使 得 编 写 应 用 程 序 更 容 易。CAsyncSocket 类 逐 个 封 装 了WinSock API, 为 高 级 网 络 程 序 员 提 供 了 更 加 有 力 而 灵 活 的 方 法。 这 个 类 基 于 程 序 员 了 解 网 络 通 讯 的 假 设, 目 的 是 为 了 在MFC 中 使 用WinSock, 程 序 员 有 责 任 处 理 诸 如 阻 塞、 字 节 顺 序 和 在Unicode 与MBCS 间 转 换 字 符 的 任 务。 为 了 给 程 序 员 提 供 更 方 便 的 接 口 以 自 动 处 理 这 些 任 务,MFC 给 出 了CSocket 类, 这 个 类 是 由CAsyncSocket 类 继 承 下 来 的, 它 提 供 了 比CAsyncSocket 更 高 层 的WinSock API 接 口。Csocket 类 和CsocketFile 类 与Carchive 类 一 起 合 作 来 管 理 发 送 和 接 收 的 数 据, 这 使 管 理 数 据 收 发 更 加 便 利。CSocket 对 象 提 供 阻 塞 模 式, 这 对 于Carchive 的 同 步 操 作 是 至 关 重 要 的。 阻 塞 函 数 比 如Receive()、Send()、ReceiveFrom()、SendTo() 和Accept() 直 到 操 作 完 成 后 才 返 回 控 制 权, 因 此 如 果 需 要 低 层 控 制 和 高 效 率, 就 使 用CasyncSock 类; 如 果 需 要 方 便, 则 可 使 用Csocket 类。 2.Win32 Internet(WinInet)API - 微 软 公 布 了 一 些 使Internet 应 用 程 序 的 设 计 比 以 前 更 快、 更 容 易 的API:WinInet API, 它 提 供 了 中 高 层 通 信 函 数, 这 使 访 问 主 要 的Internet 协 议 变 得 相 当 容 易。 这 些 函 数 在 程 序 员 和WinSock 驱 动 之 间 提 供 了 隔 离 层。 有4 类WinInet API 函 数: 通 用WinInet 函 数、WinInet 文 件 传 输 协 议(FTP) 函 数、WinInet Gopher 函 数、WinInet 超 文 本 传 输 协 议(HTTP) 函 数。 - 事 实 上,MFC 把WinInet API 和ActiveX 技 术 封 装 进 类, 使Internet 编 程 更 加 容 易, 这 些 类 包 括CInternetSession、CInternetConnection、CInternetFile、CHttpConnection、CHttpFile、CGopherFile、CFtpConnection、CGopherConnection、CFileFind、CFtpFileFind、CGopherFileFind、CGopherLocator 和CInternetException。 3.Internet 服 务 器API(ISAPI) - 微 软 的IIS 是 惟 一 与Windows NT Server 操 作 系 统 紧 密 集 成 的WWW 服 务 器, 它 作 为Internet/Intranet 服 务 器 应 用 范 围 很 广。IIS 允 许 扩 展 功 能, 这 是 通 过ISAPI 来 实 现 的,ISAPI 描 述 了 与Internet 服 务 器 之 间 的 接 口。 用ISAPI 提 供 的 工 具, 可 建 立 高 性 能、 高 效 率、 满 足 商 业 安 全 及 符 合 新 的IIS 标 准 的Internet 服 务 器。 同 样,ISAPI 在MFC 中 由 典 型 的 类 所 封 装, 包 括CHttpFilter、CHttpFilterContext、CHttpServer、CHttpServerContext、Related Classes 和CHtmlStream。 三、WinSock API 的MFC 封 装 类 一 些 网 络 应 用 程 序( 如 网 络 电 话、 多 媒 体 会 议 工 具) 实 时 性 要 求 非 常 强, 要 求 能 够 直 接 应 用WinSock 发 送 和 接 收 数 据。 这 时 设 计 者 应 该 选 择 直 接 应 用WinSock API 或 者 由MFC 封 装 的WinSock API。 新 开 发 的 应 用 程 序 中, 为 了 充 分 利 用MFC 的 优 势, 首 选 方 案 应 当 是MFC 中 的CAsyncSocket 类 和CSocket 类, 这 两 个 类 完 全 封 装 了WinSock API, 并 提 供 更 多 的 便 利。 本 文 介 绍 应 用 这 两 个 类 的 编 程 模 型, 并 引 出 相 关 的 成 员 函 数 与 一 些 概 念 的 解 释。 1.CAsyncSocket 类 和CSocket 类 简 述 附图 CAsyncSocket 类和 CSocket 类的继承关系 - CAsyncSocket 类 和CSocket 类 的 继 承 关 系 由 附 图 给 出。CSocket 类 是 由CAsyncSocket 继 承 而 来 的, 事 实 上, 在MFC 中CAsyncSocket 逐 个 封 装 了WinSock API, 每 个CAsyncSocket 对 象 代 表 一 个Windows Socket, 使 用CAsyncSocket 类 要 求 程 序 员 对 网 络 编 程 较 为 熟 悉。 相 比 起 来,CSocket 类 是CAsyncSocket 的 派 生 类, 继 承 了 它 封 装 的WinSock API。 一 个CSocket 对 象 代 表 了 一 个 比CAsyncSocket 对 象 更 高 层 次 的Windows Socket 抽 象,CSocket 类 与CSocketFile 类 和CArchive 类 一 起 工 作 来 发 送 和 接 收 数 据, 因 此 使 用 它 更 加 容 易。CSocket 对 象 提 供 阻 塞 模 式, 因 为 阻 塞 功 能 对 于CArchive 的 同 步 操 作 是 至 关 重 要 的。 在 这 里 有 必 要 对 阻 塞 的 概 念 作 一 解 释: 一 个socket 可 以 处 于“ 阻 塞 模 式” 或“ 非 阻 塞 模 式”, 当 一 个 套 接 字 处 于 阻 塞 模 式( 即 同 步 操 作) 时, 它 的 阻 塞 函 数 直 到 操 作 完 成 才 会 返 回 控 制 权, 之 所 以 称 为 阻 塞 是 因 为 此 套 接 字 的 阻 塞 函 数 在 完 成 操 作 返 回 之 前 什 么 也 不 能 做。 如 果 一 个socket 处 于 非 阻 塞 模 式( 即 异 步 操 作), 则 会 被 调 用 函 数 立 即 返 回。 在CAsyncSocket 类 中 可 以 用GetLastError 成 员 函 数 查 询 最 后 的 错 误, 如 果 错 误 是WSAEWOULDBLOCK 则 说 明 有 阻 塞, 而CSocket 绝 不 会 返 回WSAEWOULDBLOCK, 因 为 它 自 己 管 理 阻 塞。 微 软 建 议 尽 量 使 用 非 阻 塞 模 式, 通 过 网 络 事 件 的 发 生 而 通 知 应 用 程 序 进 行 相 应 的 处 理。 但 在CSocket 类 中, 为 了 利 用CArchive 处 理 通 讯 中 的 许 多 问 题 和 简 化 编 程, 它 的 一 些 成 员 函 数 总 是 具 有 阻 塞 性 质 的, 这 是 因 为CArchive 类 需 要 同 步 的 操 作。 在Win32 环 境 下, 如 果 要 使 用 具 有 阻 塞 性 质 的 套 接 字, 应 该 放 在 独 立 的 工 人 线 程 中 处 理, 利 用 多 线 程 的 方 法 使 阻 塞 不 至 于 干 扰 其 他 线 程, 也 不 会 把CPU 时 间 浪 费 在 阻 塞 上。 多 线 程 的 方 法 既 可 以 使 程 序 员 享 受CSocket 带 来 的 简 化 编 程 的 便 利, 也 不 会 影 响 用 户 界 面 对 用 户 的 反 应。 - 2.CAsyncsocket 类 编 程 模 型 - 在 一 个MFC 应 用 程 序 中, 要 想 轻 松 处 理 多 个 网 络 协 议, 而 又 不 牺 牲 灵 活 性 时, 可 以 考 虑 使 用CAsyncSocket 类, 它 的 效 率 比CSocket 类 要 高。CAsyncSocket 类 针 对 字 节 流 型 套 接 字 的 编 程 模 型 简 述 如 下: - (1) 构 造 一 个CAsyncSocket 对 象, 并 用 这 个 对 象 的Create 成 员 函 数 产 生 一 个Socket 句 柄。 可 以 按 如 下 两 种 方 法 构 造: CAsyncSocket sock;Sock.Create(); / 使 用 默 认 参 数 产 生 一 个 字 节 流 套 接 字 或CAsyncSocket*pSocket=new CAsyncSocket;int nPort=27;pSocket->Create(nPort, SOCK-DGRAM);/ 指 定 端 口 号 产 生 一 个 数 据 报 套 接 字- 第 一 种 方 法 在 栈 上 产 生 一 个CAsyncSocket 对 象, 而 第 二 种 方 法 在 堆 上 产 生CAsyncSocket 对 象。 第 一 种Create 成 员 函 数 用 缺 省 参 数 产 生 一 个 字 节 流 套 接 字, 第 二 种Create 成 员 函 数 用 指 定 的 端 口 和 地 址 产 生 一 个 数 字 报 套 接 字。Create 的 参 数 有: - 端 口,UINT 类 型。 注 意: 如 果 是 服 务 方, 则 使 用 一 个 众 所 周 知 的 端 口 供 服 务 方 连 接; 如 果 是 客 户 方, 典 型 做 法 是 接 受 默 认 参 数, 使 套 接 字 可 以 自 主 选 择 一 个 可 用 端 口; - socket 类 型。SOCK-STREAM( 默 认 值) 或SOCK-DGRAM; - socket 地 址。 例 如“” 或“202.193.64.33”。 - (2) 如 是 客 户 方 程 序, 用CAsyncSocket Connect 成 员 函 数 连 接 到 服 务 方; 如 是 服 务 方 程 序, 用CAsyncSocket Listen 成 员 函 数 开 始 监 听, 一 旦 收 到 连 接 请 求, 则 调 用CAsyncSocket Accept 成 员 函 数 开 始 接 收。 注 意:CAsyncSocket Accept 成 员 函 数 要 用 一 个 新 的 并 且 是 空 的CSocket 对 象 作 为 它 的 参 数, 这 里 所 说 的“ 空 的” 指 的 是 这 个 新 对 象 还 没 有 调 用Create 成 员 函 数。 - (3) 调 用 其 他 的CAsyncSocket 类 成 员 函 数 进 行 通 讯 管 理。 - (4) 通 讯 结 束 后, 销 毁CAsyncSocket 对 象。 如 果 是 在 栈 上 产 生 的CAsyncSocket 对 象, 则 对 象 超 出 定 义 的 范 围 时 自 动 被 析 构; 如 果 是 在 堆 上 产 生, 也 就 是 用 了new 这 个 操 作 符, 则 必 须 使 用delete 操 作 符 销 毁CAsyncSocket 对 象。 - 3.CSocket 类 编 程 模 型 - 使 用CSocket 对 象 涉 及CArchive 和CSocketFile 类 对 象。 以 下 介 绍 的 针 对 字 节 流 型 套 接 字 的 操 作 步 骤 中, 只 有 第3 步 对 于 客 户 方 和 服 务 方 操 作 是 不 同 的, 其 他 步 骤 都 相 同。 - (1) 构 造 一 个CSocket 对 象。 - (2) 使 用 这 个 对 象 的Create 成 员 函 数 产 生 一 个socket 句 柄。 在 客 户 方 程 序 中, 除 非 需 要 数 据 报 套 接 字,Create 一 般 情 况 下 应 该 使 用 默 认 参 数。 而 对 于 服 务 方 程 序, 必 须 在 调 用Create 时 指 定 一 个 端 口。 注 意:CArchive 不 能 与 数 据 报(UDP) 套 接 字 一 起 工 作, 因 此 对 于 数 据 报 套 接 字,CAsyncSocket 和CSocket 的 使 用 方 法 是 一 样 的。 - (3) 如 果 是 客 户 方 套 接 字, 则 调 用CAsyncSocket Connect 与 服 务 方 套 接 字 连 接; 如 果 是 服 务 方 套 接 字, 则 调 用CAsyncSocket Listen 开 始 监 听 来 自 客 户 方 的 连 接 请 求, 收 到 连 接 请 求 后, 调 用CAsyncSocket Accept 接 受 请 求, 建 立 连 接。 注 意:Accept 成 员 函 数 需 要 一 个 新 的 并 且 为 空 的CSocket 对 象 作 为 它 的 参 数, 解 释 同 上。 - (4) 产 生 一 个CSocketFile 对 象, 并 把 它 与CSocket 对 象 关 联 起 来。 - (5) 为 接 收 和 发 送 数 据 各 产 生 一 个CArchive 对 象, 把 它 们 与CSocketFile 对 象 关 联 起 来。 切 记CArchive 是 不 能 和 数 据 报 套 接 字 一 起 工 作 的。 - (6) 使 用CArchive 对 象 在 客 户 与 服 务 方 传 送 数 据。 (7) 通 讯 完 毕 后, 销 毁CArchive、CSocketFile 和CSocket 对 象。 三 使用MFC快速实现网络编程 其实,VC+的MFC类库中提供了CAsyncSocket这样一个套接字类,用他来实现Socket编程,是非常方便的。 本文将用一个Echo例程来介绍CAsyncSocket类的用法。 一 客户端 1 创建一个Dialog Based项目:CSockClient。 2 设计对话框 去掉Ok和Cancle两个按钮,增加ID_Connect(连接)、ID_Send(发送)、ID_Exit(关闭)按钮,增加ListBox控件IDC_LISTMSG和Edit控件IDC_EDITMSG,并按下表在ClassWizard中为CCSockClientDlg类添加变量。 ControlIDTypeMemberIDC_EDITMSGCEditm_MSGIDC_LISTMSClistBoxm_MSGS 3 CAsyncSocket类用DoCallBack函数处理MFC消息,当一个网络事件发生时,DoCallBack函数按网络事件类型:FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT分别调用OnReceive、OnSend、OnAccept、OnConnect函数。由于MFC把这些事件处理函数定义为虚函数,所以要生成一个新的C+类,以重载这些函数,做法如下: 以Public方式继承CAsyncSocket类,生成新类MySock; 为MySock类添加虚函数OnReceive、OnConnect、OnSend 4 在MySock.ccp中添加以下代码 #include "CSockClient.h"#include "CSockClientDlg.h"5 在MySock.h中添加以下代码 public: BOOL m_bConnected; /是否连接 UINT m_nLength; /消息长度 char m_szBuffer4096; /消息缓冲区6 在MySock.ccp中重载各函数 MySock:MySock()m_nLength=0;memset(m_szBuffer,0,sizeof(m_szBuffer);m_bConnected=FALSE;MySock:MySock()/关闭套接字if(m_hSocket!=INVALID_SOCKET) Close();void MySock:OnReceive(int nErrorCode) m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);/下面两行代码用来获取对话框指针CCSockClientApp* pApp=(CCSockClientApp*)AfxGetApp();CCSockClientDlg* pDlg=(CCSockClientDlg*)pApp- >m_pMainWnd;pDlg- >m_MSGS.InsertString(0,m_szBuffer);memset(m_szBuffer,0,sizeof(m_szBuffer);CAsyncSocket:OnReceive(nErrorCode);void MySock:OnSend(int nErrorCode) Send(m_szBuffer,m_nLength,0);m_nLength=0;memset(m_szBuffer,0,sizeof(m_szBuffer);/继续提请一个“读”的网络事件,接收Server消息AsyncSelect(FD_READ);CAsyncSocket:OnSend(nErrorCode);void MySock:OnConnect(int nErrorCode) if (nErrorCode=0) m_bConnected=TRUE; CCSockClientApp* pApp=(CCSockClientApp*)AfxGetApp(); CCSockClientDlg* pDlg=(CCSockClientDlg*)pApp- >m_pMainWnd; memcpy(m_szBuffer,"Connected to ",13); strncat(m_szBuffer,pDlg- >m_szServerAdr, sizeof(pDlg- >m_szServerAdr); pDlg- >m_MSGS.InsertString(0,m_szBuffer); AsyncSelect(FD_READ); /提请一个“读”的网络事件,准备接收CAsyncSocket:OnConnect(nErrorCode);7 新建对话框IDD_Addr,用来输入IP地址和Port;生成新类CAddrDlg。增加两个Edit控件:IDC_Addr、IDC_Port按下表在ClassWizard中为CAddrDlg类添加变量。 Control IDTypeMemberIDC_AddrCStringm_AddrIDC_Portintm_Port8 在CSockClientDlg.ccp中添加代码 #include "AddrDlg.h"protected:int TryCount;MySock m_clientSocket;UINT m_szPort;public:char m_szServerAdr256;9 双击IDD_CSOCKCLIENT_DIALOG对话框中的“连接”按钮,添加以下代码 void