《第4章-MFCWinSock类的编程.ppt》由会员分享,可在线阅读,更多相关《第4章-MFCWinSock类的编程.ppt(50页珍藏版)》请在三一文库上搜索。
1、第4章 MFC WinSock类的编程,4.1 CAsyncSocket类 4.2 CSocket类 4.3 CAsyncSocket类应用实例,为简化套接字网络编程,更方便地利用Windows的消息驱动机制,微软的MFC,提供了两个套接字类,在不同的层次上对Windows Socket API函数进行了封装,为编写Windows Socket网络通信程序,提供了两种编程模式。,Sockets Programming Models Based MFC,The two MFC Windows Sockets programming models are supported by the foll
2、owing classes: CAsyncSocket This class encapsulates the Windows Sockets API. CAsyncSocket is for programmers who know network programming and want the flexibility of programming directly to the sockets API but also want the convenience of callback functions for notification of network events. Other
3、than packaging sockets in object-oriented form for use in C+, the only additional abstraction this class supplies is converting certain socket-related Windows messages into callbacks. CSocket,在很低的层次上对Windows Sockets API进行了封装。 它的成员函数和Windows Sockets API的函数调用直接对应。一个CAsyncSocket对象代表了一个Windows套接字。它是网络通信
4、的端点。除了把套接字封装成C+的面向对象的形式供程序员使用以外,这个类唯一所增加的抽象就是将那些与套接字相关的Windows消息变为CAsyncSocket类的回调函数。,CAsyncSocket类,Sockets Programming Models Based MFC,CSocket This class, derived from CAsyncSocket, supplies a higher level abstraction for working with sockets through an MFC CArchive object. Using a socket with an
5、archive greatly resembles using MFCs file serialization protocol. This makes it easier to use than the CAsyncSocket model. CSocket inherits many member functions from CAsyncSocket that encapsulate Windows Sockets APIs; you will have to use some of these functions and understand sockets programming g
6、enerally. But CSocket manages many aspects of the communication that you would have to do yourself using either the raw API or class CAsyncSocket. Most importantly, CSocket provides blocking (with background processing of Windows messages), which is essential to the synchronous operation of CArchive
7、.,从CAsyncSocket类派生,是对Windows Sockets API的高级封装。CSocket类继承了CAsyncSocket类的许多成员函数,用法一致。CSocket类的高级表现在三个方面: (1)CSocket结合archive类来使用套接字。 (2)CSocket管理了通信的许多方面,如字节顺序问题和字符串转换问题。 (3)CSocket类为Windows消息的后台处理提供了阻塞的工作模式。,CSocket类,这两个类提供了事件处理函数,编程者通过对事件处理函数进行重载,可方便地对套接字发送数据、接收数据等事件进行处理。同时,可以结合MFC的其它类来使用这两个套接字类,并利用
8、MFC的各种可视化向导,从而大大简化了编程。 在MFC中,有一个名为afxSock.h的包含文件,在这个文件中定义了CAsyncSocket,CSocket,和CSocketFile这三个套接字类。,Afxsock.h,4.1 CAsyncSocket类,4.1.1 创建CAsyncSocket类对象 4.1.2 关于CAsyncSocket类可以接受并处理的消息事件 4.1.3 客户端套接字对象请求连接到服务器端套接字对象 4.1.4 服务器接受客户机的连接请求 4.1.5 发送与接收流式数据 4.1.6 关闭套接字 4.1.7 错误处理 4.1.8 其他函数,CAsyncSocket类从C
9、object类派生而来,如图4.1所示:,图4.1 CAsyncSocket类的派生关系,CAsyncSocket类的派生关系,本课程将CAsyncSocket类对象称为异步套接字对象。创建异步套接字对象一般分为两个步骤,首先构造一个CAsyncSocket对象,再创建该对象的底层的SOCKET句柄。 1创建空的异步套接字对象 通过调用CAsyncSocket类的构造函数,创建一个新的空CAsyncSocket类套接字对象,构造函数不带参数。然后必须调用它的Create成员函数,来创建底层的套接字数据结构,并绑定它的地址。,4.1.1 创建CasyncSocket类对象,有两种使用方法,会在不
10、同的位置创建。 (1)如:CAsyncSocket asock; asock.Create(); (2)如: CAsyncSocket* pa; pa = new CAsyncSocket; pa -Create();,通过调用CAsyncSocket类的Create()成员函数,创建该对象的底层套接字句柄,决定套接字对象的具体特性。调用格式为: BOOL Create( UINT nSocketPort = 0, Int nSocketType = SOCK_STREAM, Long Ievent = FD_READ|FD_WRITE| FD_OOB|FD_ACCEPT|FD_CONNECT
11、|FD_CLOSE, LPCTSTR lpszSocketAddress = NULL );,2创建异步套接字对象的底层套接字句柄,举例:创建一个使用27端口的流式异步套接字对象。 CAsyncSocket* pSocket = new CAsyncSocket; int nPort = 27; pSocket-Create( nPort, SOCK_STREAM );,创建异步套接字举例,1六种套接字相关的事件与通知消息 参数Ievent可以选用的六个符号常量是在winsock.h文件中定义的。 #define FD_READ 0x01 #define FD_WRITE 0x02 #defi
12、ne FD_OOB 0x04 #define FD_ACCEPT 0x08 #define FD_CONNECT 0x10 #define FD_CLOSE 0x20,4.1.2 关于CAsyncSocket类可以接受并处理的 消息事件,他们代表MFC套接字对象可以接受并处理的六种网络事件,当事件发生时,套接字对象会收到相应的通知消息,并自动执行套接字对象响应的事件处理函数。 (1)FD_READ事件通知:通知有数据可读。 (2)FD_WRITE事件通知:通知可以写数据。 (3)FD_ACCEPT事件通知:通知监听套接字有连接请求可以接受。 (4)FD_CONNECT事件通知:通知请求连接的套
13、接字,连接的要求已被处理(但不一定是被接受)。 (5)FD_CLOSE事件通知:通知套接字已关闭。 (6)FD_OOB事件通知:通知将有带外数据到达。,2MFC框架对于六个网络事件的处理 当上述的网络事件发生时,MFC框架作何处理呢?按照Windows的消息驱动机制,MFC框架应当把消息发送给相应的套接字对象,并调用作为该对象成员函数的事件处理函数。事件与处理函数是一一映射的。,在afxSock.h文件中的CAsyncSocket类的声明中,定义了与这六个网络事件对应的事件处理函数。 virtual void OnReceive(int nErrorCode); 对应 FD_READ事件 vi
14、rtual void OnSend(int nErrorCode); 对应 FD_WRITE事件 virtual void OnAccept(int nErrorCode); 对应 FD_ACCEPT事件 virtual void OnConnect(int nErrorCode); 对应 FD_CONNECT事件,virtual void OnClose(int nErrorCode); 对应 FD_CLOSE事件 virtual void OnOutOfBandData(int nErrorCode); 对应 FD_OOB事件 当某个网络事件发生时,MFC框架会自动调用套接字对象的对应的事
15、件处理函数。这就相当给了套接字对象一个通知,告诉它某个重要的事件已经发生。所以也称之为套接字类的通知函数(notification functions)或回调函数(callback functions)。,3重载套接字对象的回调函数 如果你从CAsyncSocket类派生了自己的套接字类,你必须重载你的应用程序所感兴趣的那些网络事件所对应的通知函数。 MFC框架自动调用通知函数,使得你可以在套接字被通知的时候来优化套接字的行为。,在服务器端套接字对象已经进入监听状态之后,客户应用程序可以调用CAsyncSocket类的Connect()成员函数,向服务器发出一个连接请求, 格式一:BOOL C
16、onnect( LPCTSTR lpszHostAddress, UINT nHostPort ); 格式二:BOOL Connect( const SOCKADDR* lpSockAddr, int nSockAddrLen );,4.1.3 客户端套接字对象请求连接到服务器端套接字对象,如果调用成功或者发生了WSAEWOULDBLOCK错误,当调用结束返回时,都会发生FD_CONNECT事件,MFC框架会自动调用客户端套接字的OnConnect()事件处理函数,并将错误代码作为参数传送给它。它的原型调用格式如下, virtual void OnConnect( int nErrorCode
17、 );,在服务器端,使用CAsyncSocket流式套接字对象,一般按照以下步骤来接收客户端套接字对象的连接请求。 (1)服务器应用程序必须首先创建一个CAsyncSocket流式套接字对象,并调用它的Create成员函数创建底层套接字句柄。这个套接字对象专门用来监听来自客户机的连接请求,所以称它为监听套接字对象。,4.1.4 服务器接受客户机的连接请求,(2)调用监听套接字对象的Listen成员函数,使监听套接字对象开始监听来自客户端的连接请求。此函数的调用格式是: BOOL Listen( int nConnectionBacklog = 5); 当Listen函数确认并接纳了一个来自客户
18、端的连接请求后,会触发FD_ACCEPT事件,监听套接字会收到通知,表示监听套接子已经接纳了一个客户的连接请求,MFC框架会自动调用监听套接字的OnAccept事件处理函数,它的原型调用格式如下, virtual void OnAccept( int nErrorCode ); 编程者一般应重载此函数,在其中调用监听套接字对象的Accept函数,来接收客户端的连接请求。,(3)创建一个新的空的套接字对象,不需要使用它的Create函数来创建底层套接字句柄。这个套接字专门用来与客户端连接,并进行数据的传输。一般称它为连接套接字,并作为参数传递给下一步的Accept成员函数。 (4)调用监听套接字
19、对象的Accept成员函数,调用格式为: virtual BOOL Accept( CAsyncSocket,当服务器和客户机建立了连接以后,就可以在服务器端的连接套接字对象和客户端的套接字对象之间传输数据了。对于流式套接字对象,使用CAsyncSocket类的Send成员函数向流式套接字发送数据,使用Receive成员函数从流式套接字接收数据。,4.1.5 发送与接收流式数据,1用Send成员函数发送数据 格式:virtual int Send( const void* lpBuf, int nBufLen, int nFlags = 0); 对于一个CAsyncSocket套接字对象,当它
20、的发送缓冲区腾空时,会激发FD_WRITE事件,套接字会得到通知,MFC框架会自动调用这个套接字对象的OnSend事件处理函数。一般编程者会重载这个函数,在其中调用Send成员函数来发送数据。,2用Receive成员函数接收数据 格式: Virtual int Receive( Void* lpBuf, Int nBufLen, Int nFlags = 0); 对于一个CAsyncSocket套接字对象,当有数据到达它的接收队列时,会激发FD_READ事件,套接字会得到已经有数据到达的通知,MFC框架会自动调用这个套接字对象的OnReceive事件处理函数。一般编程者会重载这个函数,在其中调
21、用Receive成员函数来接收数据。在应用程序将数据取走之前,套接字接收的数据将一直保留在套接字的缓冲区中。,1使用CAsyncSocket类的Close成员函数 格式:virtual void Close( ); 2使用CAsyncSocket类的ShutDown()成员函数 使用CAsyncSocket类的ShutDown()成员函数,可以选择关闭套接字的方式。将套接字置为不能发送数据,或不能接收数据,或二者均不能的状态。 格式:BOOL ShutDown( int nHow = sends );,4.1.6 关闭套接字,一般说来,调用CAsyncSocket对象的成员函数后,返回一个逻辑
22、型的值,如果成员函数执行成功,返回TRUE;如果失败,返回FALSE。究竟是什么原因造成错误呢?这时,可以进一步调用CAsyncSocket对象的GetLastError()成员函数,来获取更详细的错误代码,并进行相应的处理。 格式: static int GetLastError( ); 返回值是一个错误码,针对刚刚执行的CAsyncSocket成员函数。,4.1.7 错误处理,1关于套接字属性的函数 要设置底层套接字对象的属性,可以调用SetSocketOpt()成员函数; 要获取套接字的设置信息,可调用GetSocketOpt()成员函数; 要控制套接字的工作模式,可调用IOCtl()成
23、员函数,选择合适的参数,可以将套接字设置在阻塞模式(Blocking mode)下工作。,4.1.8 其它的成员函数,2发送和接收数据 如果创建的是数据报类型的套接字,用SendTo()成员函数来向指定的地址发送数据,事先不需要建立发送端和接收端之间的连接,用ReceiveFrom()成员函数可以从某个指定的网络地址接收数据。,发送数据SendTo的调用格式,有两种重载的形式,区别在于参数不同: int SendTo( const void* lpBuf, int nBufLen, UINT nHostPort, LPCTSTR lpszHostAddress = NULL, int nFla
24、gs = 0 ); int SendTo( const void* lpBuf, int nBufLen, const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags = 0 );,接收数据ReceiveFrom的调用格式,也有两种重载的形式,区别在于参数不同: int ReceiveFrom( void* lpBuf, int nBufLen, CString,4.2 CSocket类,4.1.1 创建CSocket对象 4.1.2 建立连接 4.1.3 发送和接收数据 4.1.4 CSocket类与CArchive类和CSocketFi
25、le类 4.1.5 发送与接收流式数据 4.1.6 关闭套接字和清除相关的对象 4.1.8 CSocket类的编程模型,CSocket类是从CAsyncSocket类派生而来的,它们的派生关系如图4.2:,图4.2 CSocket类的派生关系,分为两个步骤: (1)调用CSocket类的构造函数,创建一个空的CSocket对象。 (2)调用此CSocket对象的Create()成员函数,创建对象的底层套接字。调用格式是: BOOL Create( UINT nSocketPort = 端口号, Int nSocketPort = SOCK_STREAM | SOCK_DGRAM, LPCTST
26、R lpszSocketAddress = 套接字所用的网络地址 ); 如果打算使用CArchive对象和套接字一起进行数据传输工作,必须使用流式套接字。,4.2.1 创建CSocket对象,CSocket类使用基类CAsyncSocket的同名成员函数Connect()、Listen()、Accept()来建立服务器和客户机套接字之间的连接,使用方法相同。不同的是:CSocket类的Connect()和Accept()支持阻塞调用。比如:在调用Connect()函数时会发生阻塞,直到成功地建立了连接或有错误发生才返回,在多线程的应用程序中,一个线程发生阻塞,其他的线程仍能处理Windows事
27、件。 CSocket对象从不调用OnConnect()事件处理函数。,4.2.2 建立连接,在创建CSocket类对象后,对于数据报套接字,直接使用CSocket类的SendTo()、ReceiveFrom()成员函数来发送和接收数据。对于流式套接字,首先在服务器和客户机之间建立连接,然后使用CSocket类的Send()、Receive()成员函数来发送和接收数据,它们的调用方式与CAsyncSocket类相同。 不同的是:CSocket类的这些函数工作在阻塞的模式。比如,一旦调用了Send()函数,在所有的数据发送之前,程序或线程将处于阻塞的状态。一般将CSocket类与CArchive类
28、和CSocketFile类结合,来发送和接收数据,这将使编程更为简单。 CSocket对象从不调用OnSend()事件处理函数。,4.2.3 发送和接收数据,使用CSocket类的最大优点在于,应用程序可以在连接的两端通过CArchive对象来进行数据传输。具体做法是: (1)创建CSocket类对象 (2)创建一个基于CSocketFile类的文件对象,并把它的指针传给上面的已创建的CSocket对象。 (3)分别创建用于输入和输出的CArchive对象,并将它们与这个CSocketFile文件对象连接。 (4)利用CArchive对象来发送和接收数据。,4.2.4 CSocket类与CAr
29、chive类 和CSocketFile类,CSocket exSocket; / 创建一个空的CSocket对象。 CSocketFile* pExFile; / 定义一个CSocketFile对象指针。 CArchive* pCArchiveIn;/ 定义一个用于输入的Carchive对象指针。 CArchive* pCArchiveOut;/ 定义一个用于输出的Carchive对象指针。 exSocket.Create(); / 创建Csocket对象的底层套接字。,示例代码,/ 创建CSocketFile对象,并将CSocket对象的指针传递给它。 pExFile = new CSock
30、etFile( & exSocket,TRUE); /创建用于输入的CArchive对象 pCArchiveIn = new CArchive(pExFile, CArchive:load); /创建用于输出的CArchive对象。 pCArchiveOut = new CArchive(pExFile, CArchive:store);,图4.3 CSocket、CArchive和CSocketFile类在传输数据时的作用,在使用完CSocket对象以后,应用程序应调用它的Close()成员函数来释放套接字占用的系统资源,也可以调用它的ShutDown()成员函数来禁止套接字读写。而对于相应
31、的CArchive对象、CSocketFile对象和CSocket对象,可以将它们销毁;也可以不作处理,因为当应用程序终止时,会自动调用这些对象的析构函数,从而释放这些对象占用的资源。,4.2.5 关闭套接字和清除相关的对象,1服务器端 (1)CSocket sockServ; / 创建空的服务器端监听套接字对象。 / 用众所周知的端口,创建监听套接字对象的底层套接字句柄。 (2)sockServ.Create( nPort ); (3)sockServ.Listen(); / 启动对于客户端连接请求的监听。 (4)CSocket sockRecv; / 创建空的服务器端连接套接字对象。,4.
32、2.6 CSocket类的编程模型,/ 接收客户端的连接请求,并将其他的任务转交给连接套接字对象。 sockServ.Accept( sockRecv); (5)CSockFile* file ; file = new CSockFile( / 创建用于输出的归档对象。 / 归档对象必须关联到文件对象。,(7)arIn dwValue; / 进行数据输入。 adOut dwValue; / 进行数据输出。输入或输出可以反复进行。 (8)sockRecv.Close(); sockServ.Close(); / 传输完毕,关闭套接字对象。,2客户端 (1)CSocket sockClient;
33、/ 创建空的客户机端套接字对象。 (2)sockClient.Create( ); / 创建套接字对象的底层套接字。 (3)sockClient.Connect( strAddr, nPort ); / 请求连接到服务器。 (4)CSockFile* file ; file = new CSockFile( /创建文件对象,并关联到套接字对象。,(5)CArchive* arIn, arOut; arIn = CArchive( / 传输完毕,关闭套接字对象。,4.3 实 例 分 析,Socket Programming with MFC.doc Sending & Receiving UDP Datagrams with MFCs CAsyncSocket C+ Class.doc,作 业,针对课堂上所讲流式套接字和数据报套接字编程实例,在.Net 2005环境下进行编程:编写基于CAsyncSocket的流式套接字客户端程序和UDP发送、接收程序,将主要模块架构、工作流程及核心代码注释进行编档作为作业上交。,
链接地址:https://www.31doc.com/p-2530434.html