140 likes | 267 Views
第八章 VC 中的网络编程. 基于类的网络程序设计. MFC 支持两种 Windows Sockets 应用程序模型,这些模型隐含在两个 MFC 类中。这两个插口类为 CAsyncSocket 和 Csocket. CAsyncSocket 类.
E N D
基于类的网络程序设计 • MFC支持两种Windows Sockets应用程序模型,这些模型隐含在两个MFC类中。这两个插口类为CAsyncSocket和Csocket.
CAsyncSocket类 • CAsyncSocket类:MFC用类CAsyncSocket封装了Windows Sockets API,它主要是为网络程序设计人员提供的,想直接利用Windows Sockets API的灵活性,但是又想利用回调函数的方式来方便地处理网络事件。在C++中,除了将插口封装成面向对象的形式外,所做的唯一抽象是:将与插口相关的Windows消息转换成回调函数。 • 当一个网络事件发生时,经过MFC的消息循环,就由CAsyncSocket的DoCallBack函数按网络事件的类型:FD_READ,FD_WRITE,FD_OOB,FD_ACCEPT,FD_CONNECT和FD_CLOSE来分别调用OnReceive(),OnSend(),OnOutOfBandData(),OnAccept(),OnConnect()和OnClose()函数。MFC把这些事件处理函数定义为虚函数,在编程时,必须重载想要处理的网络事件函数。
使用CAsyncSocket类进行网络应用程序设计 • 使用CAsyncSocket类进行网络应用程序设计步骤如下: • 1、建立一个CAsyncSocket对象并用这个对象产生Socket句柄:构造CAsyncSocket对象可以在栈,也可以在堆中。产生Socket句柄时,对Client端要用缺省的参数去创建一个句柄,对Server端必须用指定的一个入口参数去创建句柄。 • Server端: CAsyncSocket srvrSocket; Int nPort=21; srvrSocket.Create(nPort,SOCK_STREAM); • Client端: Csocket clientSocket; clientSocket.Create();
2、如果是Client方的Socket,用Connect函数方法去连接一个Server方的Socket对象;如果是Server方的Socket对象,调用Listen函数开始监听消息,一旦有Client端的Socket试图连接,就调用Accept函数来接收连接请求。2、如果是Client方的Socket,用Connect函数方法去连接一个Server方的Socket对象;如果是Server方的Socket对象,调用Listen函数开始监听消息,一旦有Client端的Socket试图连接,就调用Accept函数来接收连接请求。 • Server端: srvrSocket.Listen(); 重载OnAccept函数处理FD_ACCEPT事件,在这里调用Accept函数,当调 用Accept函数时,需传递一个参数给新对象,必须先构造这个对象,但 是不要调用这个对象的Create函数。 srvrSocket.OnAccept(); • Client端: clientSocket.Connect(strAddr,nPort);
3、调用CAsyncSocket对象的成员函数来执行通信任务。3、调用CAsyncSocket对象的成员函数来执行通信任务。 • 4、当通信结束时,删除CAsyncSocket对象。如果在栈中构造,那么,当对象超出范围时,会自动调用析构函数;如果使用new运算符在堆中构造,必须调用delete运算符。 程序实例
CSocket类 • CAsyncSocket类编程还是比较复杂,需要编程者编写底层函数来进行通信操作,而CSocket类提供了一个高级的Socket支持,它运用了MFC的序列化类来提供和传输Socket对象。 • CSocket类的PumpMessage函数进行阻塞处理,进行通信时又使用MFC的序列化协议,即由CArchive类管理了很多底层的功能,使得程序员不需要考虑网络字节顺序和字符串的转换问题,所以编程的难度得到了降低,又很好地使用了MFC的序列化功能。
CSocket类的编程模式 • 1、建立一个CSocket对象 • Server端: Csocket srvrSocket; • Client端 CSocket clientSocket; • 2、用这个对象产生以下的句柄: • Server端:必须用指定的一个入口参数去创建句柄。 srvrSocket.Create(nPort); • Client端:用缺省的参数去创建一个句柄。 clientSocket.Create();
3、如果是Client方的Socket,用Connect函数方法去连接一个Server方的Socket对象;如果是Server方的Socket对象,调用Listen函数开始监听信息,一旦有Client端的Socket试图连接,就调用Accept函数来接收连接请求。3、如果是Client方的Socket,用Connect函数方法去连接一个Server方的Socket对象;如果是Server方的Socket对象,调用Listen函数开始监听信息,一旦有Client端的Socket试图连接,就调用Accept函数来接收连接请求。 • Server端: srvrSocket.Listen(); //构造一个新的Socket对象,注意不要调用这个对象的Create函数。 CSocket sockRecv; srvrSocket.Accept(sockRecv); • Client端 clientSocket.Connect(strAddr,nPort);
4、创建一个CSocket派生的类CSocketFile。 • Server端: CSocketFile file(&sockRecv); • Client端: CSocketFile file(&clientSocket); • 5、创建一个与CSocketFile关联的CArchive对象,用这个对象来接收和发送数据。 • Server端: CArchive arIn(&file,CArchive::load); Carchive arOut(&file,CArchive::store); • Client端: CArchive arIn(&file,CArchive::load); Carchive arOut(&file,CArchive::store);
6、用CArchive对象在Client和Server方两端传递数据。下面以传递DWORD类型的数据为例。6、用CArchive对象在Client和Server方两端传递数据。下面以传递DWORD类型的数据为例。 • Server端: arIn>>dwValue; arOut<<dwValue; • Client端: arIn>>dwValue; arOut<<dwValue; • 7、当通信结束时,删除CArchive,CSocketFile和Csocket对象。 程序实例
远程监控系统的原理 • 远程监视 • 主控机每0.4秒向受控机发一个屏幕刷新命令,受控机便抓取当前屏幕,并用压缩算法对当前屏幕进行压缩形成数据流后,通过tcp/ip协议将数据传输到主控机;主控机用相应的图像解压算法将数据流还原成原图像文件并显示。这样高频率地刷新屏幕,便实现了实时地监视屏幕。 • 远程控制 • 每当主控机用鼠标或键盘控制受控机的同时,主控机将控制的具体操作以及操作的坐标位置以命令的形式发给受控机。 • 例如:在主控机用鼠标左键点击主控机屏幕中被监视的受控机屏幕的(352,285)位置的同时,主控机通过tcp/ip协议将以下命令发送到受控机:SendCommand(m_hWnd,1,“WM_LBD;x;y;1;0;\0”); • 其中,”WM_LBD”表示一个Windows Message-- Left Button Down(鼠标左键被点击一下);x和y表示点击位置的坐标值。当受控机收到这个命令字后,根据命令字内容生成一个相应的Windows Message并将它加入消息队列。
受控机 启动服务 初始化插口,绑定地址,并准备好接收连接 抓取当前屏幕,得到依赖于设备的位图DDB DDBddDDddDDDDB(Device-Dependent Bitmap) 每400毫秒抓取一次屏幕,发送给主控机 将DDB转化为设备无关位图DIB(Device-Independent Bitmap) 用图像压缩算法压缩DIB,得到数据流 主控机 用插口将数据流发送给主控机 建立连接 建立插口,和受控机建立连接 不断接收来自受控机的数据流 用图像解压算法还原数据流,得到图像文件 数据流 监视窗口将图像更新显示 远程监视
主控机 受控机 主控机的监视窗口一旦有对受控机的操作 每当收到主控机发送的命令字,分析参数得到操作种类和操作位置 命令字 得到操作的具体位置(x,y)和操作的具体种类,如鼠标双击或键盘A键被KeyDown, 将操作位置转换成屏幕绝对坐标 若是10类鼠标操作之一,用mouse_event函数产生此事件并加入消息队列 若是键盘类操作,用keybd_event函数产生此事件并加入消息队列 用插口将上面的信息以命令字的形式发送给受控机 消息被执行,远程控制也就得到了实现 远程控制