友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
VC语言6.0程序设计从入门到精通-第43部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
了能与 WinSock1。1 更好地实现其兼容性,WinSock2。0 在 WinSock1。1 基础上作了向后兼容,
即源码和二进制代码。这就实现了 WinSock 应用程序和任何版本的 WinSock 实现之间的最大
的互操作性,同时也减轻了 WinSock 应用程序使用者、网络协议栈提供者和服务提供者的负
担。
11。2 网络应用程序
11。2。1 网络应用程序的基本模型
在 TCP/IP 网络应用中,通信的两个进程间相互作用的主要模式是客户机/服务器模式
(Client/Server model ),即客户向服务器发出服务请求,服务器接收到请求后,提供相应的服
·281 ·
…………………………………………………………Page 293……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
务。客户机/服务器模式的建立基于以下两点:
(1)建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而造
就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。
(2 )网络间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不存在共
享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同
步,这就是基于客户机/服务器模式的 TCP/IP 。
客户机/服务器模式在操作过程中采取的是主动请求方式,具体操作步骤如下。
o 首先服务器方要先启动,并根据请求提供相应服务:
o 打开一通信通道并告知本地主机,它愿意在某一端口上接收客户请求。
o 等待客户请求到达该端口。
o 接收到重复服务请求,处理该请求并发送应答信号。接收到并发服务请求,要激活一
新进程来处理这个客户请求 。新进程处理此客户请求,并不需要对其他请求作出应答。
服务完成后,关闭此进程与客户的通信链路,并终止该进程。
o 返回第二步,等待另一客户请求。
o 关闭服务器。
客户方的主要操作步骤如下:
o 打开一通信通道,并连接到服务器所在主机的指定端口。
o 向服务器发服务请求报文,等待并接收应答;继续提出请求。
o 请求结束后关闭通信通道并终止。
在客户机/服务器编程模型下,又分为面向连接的编程模型和无连接的编程模型。
o 面向连接的编程模型:当服务器程序的套接字创建并初始化完毕时,它先进入休眠状
态,直到有客户机向该服务器程序提出连接请求。这时,服务器程序被“唤醒”并开
始响应客户机提出的连接请求,双方协商数据由谁来接收和由谁来发送。在数据传输
完毕时,双方再分别关闭连接并释放因创建套接字而占用的资源。
o 无连接的编程模型:在传输数据前,不需要事先进行连接,有数据就进行发送,但却
不对数据的顺序和正确性负责。相对于面向连接的模型,它的传输效率较高,但准确
率稍低。
11。2。2 建立套接字对象
函数 socket()可以创建一个 socket 对象,socket()函数的原型如下:
SOCKET socket(int af; int type; int protocol );
各参数意义如下。
o af :协议的地址家族。在 Windows 操作系统中,它的取值只能是 AF_INET ,表示该套
接字在 Internet 域中进行通信。
o type :套接字类型。当第一个参数 af 取值为 AF_INET 时,它只有 3 种取值,如表 11…1
所示。
o protocol :指定网络协议。具体取值如表 11…2 所示。
如果创建成功,则返回一个创建好的套接字,如果创建失败,则返回 INVALID_SOCKET,
详细信息可以通过调用函数 WSAGetLastError()查看错误信息。
·282 ·
…………………………………………………………Page 294……………………………………………………………
第 11 章 网络编程
表 11…1 套接字类型取值及说明
取值 类型 说明
面向连接、可靠的数据传输服务,数据无差错发送,且按
SOCK_STREAM TCP
发送顺序接收;数据被看作是字节流,无长度限制
无连接服务。数据包以独立包形式发送,不提供无错保证,
SOCK_DGRAM UDP
数据可能丢失,且接收顺序混乱
SOCK_RAW Raw sockets 允许对较低层协议,如 IP、ICMP 直接访问
表 11…2 网络协议取值与套接字类型关系
套接字类型 网络协议
TCP IPPROTO_IP
UDP IPPROTO_UDP
Raw sockets IPPROTO_RAW
11。2。3 绑定地址
创建好 Socket 后,通常要将本地地址附加到所创建的套接字上以便能够有效地标识此套
接字。这个过程由 bind() 函数来实现,它的原型如下:
int bind(SOCKET s; const struct sockaddr FAR *name; int namelen);
各参数意义如下:
o s:要绑定的套接字。
o name :用来赋予套接字地址。
o namelen :name 参数的长度。
其中,sockaddr 结构如下:
struct sockaddr_in
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero'8';
};
各参数意义如下。
o sin_family:在 Windows 操作系统中,此值为 AF_INET 。
o sin_port:服务的端口号。
o sin_addr:保存 IP 地址。
o sin_zero'8':其值为 0,只起填充作用。
如果绑定成功,则返回 0 ;出错则返回 SOCKET_ERROR。
11。2。4 建立连接
函数 connect()可以实现客户机和服务器的连接,其原型如下:
int connect(SOCKET s; const struct sockaddr FAR *name; int namelen);
各参数意义如下。
·283 ·
…………………………………………………………Page 295……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
o s:进行连接的套接字。
o name :要连接服务器的套接字地址结构。
o namelen :name 参数的长度。
如果连接成功,此函数返回 0 ;失败则返回 SOCKET_ERROR。
对于服务器来说,当客户机发来连接请求后,服务器要调用 accept()函数来响应对方的连
接请求,该函数原型如下:
SOCKET accept(SOCKET s; struct sockaddr FAR *addr; int FAR *addrlen);
各参数意义如下。
o s:处在监听(下小节介绍)模式下的套接字。
o addr :在函数调用过程中被填充发出连接请求的客户机的 IP 地址信息。
o addrlen :addr 参数的长度。
如果成功,则返回一个新的套接字,它对应于已经接受的那个客户机连接。对于该客户
机所有的后续操作,都使用这个新的套接字。原来的套接字则仍处于监听模式,继续接受其
他客户机的连接。如果失败,则返回 INVALID_SOCKET 。
11。2。5 监听 socket
对于服务器端来说,在它接受客户机的连接之前,首先要监听。只有进入了监听模式,
才能接受来自客户机的连接。这一点可以通过 listen()函数实现,它的原型如下:
int listen(SOCKET s; int backlog);
各参数意义如下。
o s:进行监听的套接字。
o backlog :正在等待连接的最大队列的长度。如果 backlog 的值为 3,有 4 个客户机同
时发出连接请求,则前 3 个会放在等待连接队列中,最后一个将被忽略。
如果函数成功,则返回 0 ;否则返回 SOCKET_ERROR。
11。2。6 数据传输
当客户机和服务器的连接建立起来以后,便可以进行数据的传输。数据的传输是网络通
信的最终目的,前面所作的工作就是为了客户机可以和服务器传输数据。数据传输又包括数
据发送和数据接收。
1.数据发送
数据发送是通过 send()函数来实现的,它的原型如下:
int send(SOCKET s; const char FAR *buf; int len; int flags );
各参数意义如下。
o s:已经建立连接的套接字。
o buf :字符缓冲区,区内包含即将发送的数据。
o len :缓冲区内的字符数目。
o flags:指定数据传输方式,取值可为 0、MSG_DONTROUTE 和 MSG_OOB ,或者是
·284 ·
…………………………………………………………Page 296……………………………………………………………
第 11 章 网络编程
这些取值进行按位或运算的结果。其中,0 表示无特殊行为;MSG_DONTROUTE 表
示传输层不要将它发出的包路由出去;MSG_OOB 表示数据应该被带外发送。
如果发送成功,则返回发送的字节数,如果失败则返回 SOCKET_ERROR。
2 .数据接收
数据接收通过函数 recv()实现,其原型如下:
int recv(SOCKET s; const char FAR *buf; int len; int flags );
各参数意义如下。
o s:准备接收数据的套接字。
o buf :指向即将接收数据的字符缓冲区的指针。
o len :缓冲区的大小。
o flags:指定传输控制方式,取值可为 0、MSG_PKKE 和 MSG_OOB ,或者是这些取值
进行按位或运算的结果 。其中,0 表示无特殊行为;MSG_PKKE 表示把数据从接收端
口复制到接收缓冲区中,并且没有从系统缓冲区中将数据删除;MSG_OOB 表示数据
是带外发送的。
如果接收成功,则返回接收的字节数,如果失败则返回 SOCKET_ERROR。
11。3 WinSock 类
在上一节中简单介绍了直接利用 WinSock API 进行网络传输的基本步骤以及主要函数的
使用方法,而实际利用 Visual C++ 6。0 开发网络应用程序的时候,很少直接利用这些 API 进
行编程,因为 MFC 已经把这些 API 都封装到 MFC 提供的类中了。本节将详细介绍在网络编
程中经常用到的 MFC 提供的两个类,即 CAsyncSocket 类和 CSocket 类。它们的继承关系如
图 11…1 所示。
图 11…1 CAsyncSocket 类和 CSocket 类的继承关系
11。3。1 CAsyncSocket 类
CAsyncSocket 类在很低的级别上封装了 Windows Socket API ,该类可以使程序员用面向
对象的方法进行 Socket 编程,而且可以非常方便地调用其他 MFC 对象。这个类要求程序员
对 Socket 编程有较为深入的了解,要面对和在直接使用 Windows Socket API 进行程序设计时
一样的问题,如阻塞处理、网络字节顺序等。因为 CAsyncSocket 类几乎是一一对应地封装了
Windows Socket API ,因此具有直接调用 WinSock API 的灵活性。
要使用一个 CAsyncSocket 对象,则先调用它的构造函数,然后调用 Create()函数,以创
建一个套接字句柄(SOCKET 类型)。CAsyncSocket 对象既可以在栈中,也可以在堆中。对
·285 ·
…………………………………………………………Page 297……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
于一个服务器套接字调用 Listen()成员函数进行监听,对于一个客户套接字调用 Connect()成
员函数来请求连接。在接收一个连接请求时,服务器套接字应该调用一个 Accept() 函数来接
收连接请求。完成之后,如果 CAsyncSocket 对象在栈中构造,则当对象超出范围时,会自动
调用析构函数;如果是在堆上被创建的,必须调用 delete 来删除此对象。
CAsyncSocket 类的主要成员函数如表 11…3 所示。
表 11…3 CAsyncSocket 类主要成员函数及说明
函数 说明
CAsyncSocket 构造函数
Create 创建一个 Socket
Attach 对 CAsyncSocket 对象附加套接字句柄
Detach 从 CasyncSocket 对象除去套接字句柄
FromHandle 返回 CasyncSocket 对象的指针,给出套接字句柄
GetLastError 获得上一次运行失败的状态
GetPeerName 获得与套接字连接的对等套接字的地址
GetSockName 获得套接字的本地名
GetSockOpt 获得套接字选项
SetSockOpt 设置套接字选项
Accept 接受套接字上的连接
AsyncSelect 请求对于套接字的事件通知
Bind 给套接字绑定本地地址
Close 关闭套接字
Connect 与对等套接字建立连接
IOCtl 控制套接字模式
Listen 建立套接字,侦听即将到来的连接请求
Receive 从套接字接收数据
ReceiveFrom 接收数据报并且存储资源地址
Send 给连接套接字发送数据
SendTo 给特定目的地发送数据
ShutDown 使套接字上的 Send 和/或 Receive 调用无效
OnAccept 通知侦听套接字,它可以通过调用 Accept ,接受挂起连接请求
OnClose 通知套接字,关闭对它的套接字连接
OnConnect 通知连接套接字,连接尝试已经完成,无论成功或失败
OnOutOfBandData 通知接收套接字,在套接字上有带外数据读入,通常是忙消息
OnReceive 通知侦听套接字,通过调用 Receive 恢复数据
OnSend 通知套接字,通过调用 Send,它可以发送数据
除了上面的成员函数,CAsyncSocket 类还有一个数据成员 m_hSocket ,它是一个 SOCKET
句柄,记录了 CAsyncSocket 类上附加的套接字。
11。3。2 CSocket 类
CSocket 类是 CAsyncSocket 类的派生类,它最大的特点是提供了可以同 CArchive 和
CSocketFile 这两个类协同工作的接口。其中 CArchive 类是一个存档类,它是将用户的数据
保存为永久性存储对象的一种技术,在此它是用于同 CSocketFile 类相关联而提供数据传输文
件化的一种技术 。而 CSocketFile 类是一种特殊的文件对象,常用它来通过套接字进行数据的
传递,它所提供的接口同普通文件类的接口基本上是一致的 。也就是说,用户在使用 CSocket
类的时候,不必再像使用 CAsyncSocket 类时不得不面对一大堆繁琐的工作,而只需像读写一
·286 ·
…………………………………………………………Page 298……………………………………………………………
第 11 章 网络编程
般文件一样直接进行数据的读取就可以了。本章主要讲述网络编程,因此本小节主要介绍
CSocket 类,而 CArchive 类和 CSocketFile 类的相关信息请读者自行查阅相关资料。
1.CArchive 对象与串行化技术
CArchive 对象是 MFC 中专门帮助程序员处理归档对象的类,它最主要的作用就是把内
存中的数据保存到永久存储介质中,这样程序员就不必担心使用的到底是套接字还是文件了。
而为了实现 CArchive 与 CSocket 之间的连接,必须使用 CSocketFile 作为中间的转化媒质。
在实际工作中 CSocketFile 对象负责连接到一个 CSocket 对象,而 CArchive 对象负责管理缓
冲区。当发送归档对象的缓冲区被填满时,相关的 CSocketFile 对象会将缓冲区的内容取出,
并清空与套接字相关的归档缓冲区。当接收归档对象的缓冲区被填满时,CSocketFile 对象将
停止读出直到缓冲区可用。
2 .用 CSocket 类的编程步骤
用 CSocket 类进行网络编程的基本步骤如下。
o 构造服务器和客户机套接字对象。
o 调用 Create()函数创建套接字。
o 服务器调用 Listen() 函数监听客户机的连接请求;客户机调用 Connect()函数向服务器
发出连接请求。
o 服务器监听到客户机的连接请求时,先创建一个新的套接字,然后调用 Accept() 函数
接收客户机的连接请求。
o 服务器和客户机的套接字对象分别建立一个与之联系的 CSocketFile 对象。
o 服务器和客户机的套接字对象分别创建一个与 CSocketFile 相联系的 CArchive 对象,
以便进行数据传输。
o 使用 CArchive 对象在服务器和客户机套接字之间进行数据传输。
o 当任务完成后,销毁 CArchive、CSocketFile 和 CSocket 对象。
注意:由于 CArchive 对象只能单向传送数据,所以在实际使用的时候必须定义两个 CArchive 对
象,分别用于数据的发送和接收。
3 .CSocket 类的主要成员函数
CSocket 类是从 CAsyncSocket 类继承来的,除了 CAsyncSocket 类的成员函数,CSocket
类还主要有以下成员函数,如表 11…4 所示。
表 11…4 CSocket 类主要成员函数及说明
函数 说明
CSocket 构造一个 CSocket 对象
Create 创建一个 Socket
IsBlocking 确定一个阻塞调用是否在进行中
FromHandle 返回一个指向 CSocket 对象的指针,给出一个 Socket 句柄
Attach 将一个 Socket 句柄与一个 CSocket 对象连接
CancelBlockingCall 取消一个当前在进行中的阻塞调用
OnMessagePending 当等待完成一个阻塞调用时调用此函数来处理未处理的消息
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!