Transcript Document

第7章
网络编程
学习目标

了解网络编程的方法

理解流式套接字和数据报套接字的区别

理解Windows Sockets的工作原理

了解两种不同的通信方式

掌握利用MFC CSocket类进行网络编程的方法

了解利用MFC CAsyncSocket类进行网络编程的方法
7.1 网络编程概述

7.1.1 Windows Sockets规范
 Windows Sockets(即WinSock)规范是90年代初
Microsoft公司联合其他几家大公司共同制定的—套在
Windows下的二进制兼容网络编程接口规范。
 Windows Sockets规范制定的本意是将基础网络抽象出来 。
 遵守Windows Sockets规范的网络软件,称之为与
windows Sockets兼容。
7.1.2 VC++ 2005网络编程


利用Windows Sockets 网络编程的方法
1.利用Windows Sockets API进行网络编程
 麻烦,但灵活
2.利用MFC提供的WinSock类进行网络编程
在MFC中,提供了两个类用来实现对Windows Socket
API的封装,从而实现网络编程
(1)CAsyncSocket类
 CAsyncSocket,顾名思义是指采用了异步(非阻塞)套
接字的类。该类主要是提供给那些具有一定网络编程经
验,希望同时拥有Winsock API编程的灵活性和类库编程
便利性的用户的。
(2)CScoket类(阻塞)
CScoket类是CAsyncSocket类的派生类,该类对
Windows Sockets API进行了更多的封装,并且
利用CArchive类进行数据传输,从而使利用该类
进行数据传输的过程与MFC的串行化一致。
7.2 套接字

套接字(Socket)是一个通信终结点,它是Windows
Sockets应用程序用来在网络上发送或接收数据包的对象。
一个套接字有自己的类型,并有一个与之相关的应用程序,
它还可以有自己的名字。
7.2.1 流式套接字

使用流式套接字的过程:
 在两个通信节点间建立连接
 节点通过这个连接进行通信
 通信完毕后取消连接

流式套接字提供了双向的数据流,并且保证数据流的传输是
可靠的、有序的(即:传输的数据顺序的正确性)、无重复的
(即:数据包只被传送一次)

最大特点是通信信息能保证按顺序无遗漏地到达目的地。
7.2.2 数据报套接字

数据报套接字也提供双向的数据传输,与流式套接字不同,
它用于实现无连接的通信方式。

在传输可靠性要求不高的信息或者通信量较少的信息,则可
采用数据报套接字。
7.2.3 IP地址和端口

IP地址是一台计算机在网络上的地址,是一个32位的数字
 如202.204.125.5就是由十进制描述的一个IP地址

端口用于标识进程,同一机器上不同的应用程序有不同的端
口,则通过“IP地址+端口”的方式可以唯一标识机器的应
用程序。
7.3 Windows Sockets的工作原理

Windows Sockets的工作方式为客户/服务器模式

根据连接的方式分为
 面向连接——流式套接字
 无连接——数据报套接字
7.3.1 面向连接的通信方式
服务器
创建并初始化套接字,
指定端口(socket)
客户端
创建并初始化套接字,
指定要连接的端口(socket)
监听客户端的请求(listen)
请求建立连接(connect)
接受连接请求(accept)
发送接收数据(send、recv)
发送确认信息
发送接收数据(send、recv)
销毁套接字,关闭连接
销毁套接字,关闭连接
(closesocket)
(closesocket)
图7-1 面向连接的通信方式
7.3.2 无连接的通信方式
服务器
客户端
创建并初始化套接字(socket)
创建并初始化套接字(socket)
向服务器发送请求(sendto)
接受请求,进行处理
(recvfrom、sendto)
发送结果
接收结果(recvfrom)
销毁套接字,关闭连接
销毁套接字,关闭连接
(closesocket)
(closesocket)
图7-2 无连接的通信方式
7.5 基于MFC的Windows Sockets编程

7.5.1 编制基于流式套接字网络应用程序的步骤
 1.服务器端
 服务器端应用程序的设计过程如下:
(1)从CSocket类派生两个新类,假设一个新类
的名称为CServeSocket,另一个新类的名称为
CAcceptSocket。其中,CServeSocket套接字用来
监听连接请求,CAcceptSocket套接字是真正用于
与客户端进行连接、接收发送数据的套接字。
(2)创建一个CServeSocket类对象。
 (3)调用CSocket::Create函数创建一个CServeSocket
套接字,并指定一个端口,端口号一般要大于1024。
 (4)调用CSocket::Listen函数侦听端口。
 (5)在CServeSocket中添加虚函数OnAccept。在
OnAccept函数中为每一个连接进来的客户端创建一个
新的CAcceptSocket类对象专门用于读写。
 (6)在用于读写的CSocket派生类CAcceptSocket的
OnReceive函数中进行读写操作。
 (7)通讯结束时,调用读写套接字的Close函数关闭
为各个客户端分配的读写套接字。
 2.客户端
 客户端应用程序的设计过程如下:
 (1)创建一个CSocket类的派生类,用于连接和读写,假设
新类的名称为CClientSocket。
 (2)调用CSocket::Create函数创建套接字。
 (3)调用CSocket::Connect函数连接到服务器的指定端口。
 (4)调用CSocket::Send函数发送数据,进行发送数据的操
作
 (5)在CClientSocket中添加虚函数onReceive,在该函数中
进行读操作。
 (6)在结束通讯时,调用CSocket::Close函数关闭套接字。
7.5.2 编制基于流式套接字的网络应用程序

【例7-1】编写两个程序,一个用于模拟服务器端的程序
Mysev,一个用于模拟客户端的程序Myclient,这个网络应
用程序的功能很简单,只是实现服务器和客户端的通信。当
客户端连接上服务器端时,给服务器发送消息:“服务器,
你好!”,服务器向客户端发送消息:“客户端,你好!”。
服务器端程序的运行结果如图7-4所示,客户端程序的运行
结果如图7-5所示。客户端与服务器进行连接后,相互发送
信息后的运行结果分别见图7-6和图7-7。
图7-4 服务器端程序Mysev的运行结果
图7-6 服务器端程序接收到的信息
图7-5 客户端程序Myclient的运行结果
图7-7 客户端程序接收到的信息

程序的实现过程如下:
 1.服务器端应用程序设计
 (1)利用MFC应用程序向导新建一个基于对话框的
应用程序Mysev
图7-8 为应用程序Mysev添加套接字支持
 (2)添加菜单资源
 (3)添加控件和关联的成员变量
 (4)添加套接字类型
 (5)建立套接字类与对话框类的关联
 (6)在对话框中初始化套接字并监听连接请求
 (7)接受连接请求
 (8)接收信息
 (9)关闭连接
 2.客户端应用程序设计
 (1)创建一个基于对话框的应用程序Myclient,在高级功能中
选择“Windows 套接字支持”,同服务器端应用程序的第一步。
 (2)添加菜单资源
 (3)添加控件和关联的成员变量
 (4)添加套接字类型
 (5)建立套接字类与对话框类的关联
 (6)初始化套接字并建立连接
 (7)接收信息
 (8)发送消息
 (9)关闭连接
 (10)编译并运行程序
7.5.3 编制基于数据报套接字网络
应用程序的步骤


基于数据报套接字的网络通信应用程序的服务器和客户端
遵循同样的编程方法。
具体的编程方法如下:
 (1)如果服务器(客户程序)需要读取客户的数据,则
创建一个CAsyncSocket类的派生类,并生成 该类的对
象;如果服务器(客户程序)仅发送数据,则直接生成一
个CAsyncSocket类对象。
 (2)调用CAsyncSocket::Socket函数创建一个数据报
类型的套接字。
 (3)调用CAsyncSocket::SetSockOpt函数设置端口可
重用。
 (4)设置一个端口号,并调用CAsyncSocket::Bind函数
将该端口捆绑到本地地址。
 (5)调用CAsyncSocket:: SetSockOpt函数设置端口属性,
允许传输广播信息。
 (6)调用CAsyncSocket::SendTo函数发送数据
 (7)在OnReceive()函数中调用ReceiveFrom函数读取客
户方发送的数据。
 (8)通信结束后,调用CAsyncSocket::Close函数关闭套
接字。
7.5.4 编制基于数据报套接字的
网络应用程序

【例7-2】创建两个应用程序,实现以无连接方式发送和接
收数据。程序的运行结果如下图所示。
图7-14 无连接方式发送和结束数据的结果

1.服务器端应用程序设计
 (1)利用MFC应用程序向导新建一个基于对话框的应用
程序MyUDPsever,在高级功能中选择“Windows 套接
字支持”。
 (2)修改应用程序主窗口
IDD_MYUDPSEVER_DIALOG对话框的布局。删除原
有的【取消】按钮,保留原有的【确定】按钮,将【确
定】按钮的“Default Button”属性设置为false。
 (3)添加一个名为IDD_PORT_DIALOG的对话框,为
该对话框添加相应的基于CDialog类的CPortDlg类,该对
话框被用于输入通讯端口号。
 (4)修改主窗口类CMyUDPseverDlg,在该类中进行通
讯。
 (5)在CMyUDPseverDlg类中添加WM_DESTROY类的
消息处理函数OnDestroy,在该函数中关闭套接字

2.客户端应用程序设计
 (1)利用MFC应用程序向导新建一个基于对话框的
应用程序MyUDPclient,在高级功能中选择
“Windows 套接字支持”。
 (2)修改应用程序主窗口的
IDD_MYUDPCLIENT_DIALOG对话框资源的布局。
删除原有的【取消】按钮,保留原有的【确定】按钮
 (3)由于本示例客户端需要从服务器读取数据,因
此从CSocket类派生一个类CClientSocket,该类用于
读取数据。
 (4)添加自定义消息宏。当CClientSocket类对象读取了
数据后,需要通过自定义消息将数据发送给应用程序主
窗口。
 (5)对CClientSocket类进行修改
 (6)创建一个ID为IDD_PORT_DIALOG的对话框,并
生成相应的基于CDialog类的派生类CPortDlg。
 (7)创建一个ID为IDD_TRY_DIALOG的对话框,并生
成相应的基于CDialog类的派生类CTryDlg。
 (8)修改MyUDPclientDlg类,添加成员变量和成员函数。
7.6 综合实例:聊天室

【例7-3】创建基于客户/服务器模式的聊天室应用程序。这
个应用程序包括客户端的应用程序和服务器端的应用程序。
(a)服务器端
(b)一个客户端
7.6.1 服务器端应用程序的功能介绍

等待用户连接

通知所有在线用户新登陆用户信息

中转消息

当用户离线时通知所有在线用户
7.6.2 客户端应用程序的功能介绍

获得连接参数后与服务器建立连接

发送/接收消息

断开时通知服务器
7.6.3 服务器端应用程序的编写过程

(1)利用MFC应用程序向导新建一个基于对话框的应用程序
ChatRoom,在高级功能中选择“Windows套接字支持”。

(2)修改应用程序主窗口IDD_CHATROOM_DIALOG对话框的
布局。

(3)添加一个头文件tagHeader.h

(4)添加一个基于CSocket的类CClientSocket,用于和客户端进
行数据交换。

(5)添加一个基于CSocket的类CServerSocket,用于接收客户端
的连接。

(6)修改CChatRoomDlg类的代码

(7)编译并运行程序
7.6.4 客户端应用程序的编写过程

(1)利用MFC应用程序向导新建一个基于对话框的应用程序
ChatClient,在高级功能中选择“Windows套接字支持”。

(2)修改应用程序主窗口IDD_CHATCLIENT_DIALOG对话框的布局。

(3)由于用户登录时需要添加服务器地址、自己的用户名等信息,所
以添加一个对话框资源,其ID为IDD_LOGIN_DIALOG,并为该对话框
添加基类为CDialog的派生类CLoginDlg。

(4)同服务器端类似,添加一个头文件tagHeader.h

(5)添加一个基于CSocket类的派生类CClientSocket,用于完成数据的
发送和接收。

(6)对类CChatClientDlg进行修改 。

(7)编译并运行程序 。