分布式实验报告张莹127129.docx
- 文档编号:9275824
- 上传时间:2023-02-04
- 格式:DOCX
- 页数:40
- 大小:2.83MB
分布式实验报告张莹127129.docx
《分布式实验报告张莹127129.docx》由会员分享,可在线阅读,更多相关《分布式实验报告张莹127129.docx(40页珍藏版)》请在冰豆网上搜索。
分布式实验报告张莹127129
实验:
仿真组件对象
实验目的
1.学习掌握开发编译器中性、可维护、可升级的组件对象的基本原理、基本方法;
2.学习分别使用异种编译器开发组件的服务器端和客户端。
实验内容
使用VC开发一个以DLL作为载体的仿真COM对象,此对象支持多个接口.每个接口支持不同的功能.使用BC开发一个客户,创建此仿真COM对象,并调用它的不同接口的功能.要求在试验过程中主要完成如下工作:
1.验证名字改编造成的编译器依赖性.
2.验证头文件的改变带来的DLL升级的问题.
3.验证接口类带来的升级便利.
4.验证普通析构函数带来的编译器依赖性..
5.验证普通析构函数带来的内存泄漏.
6.验证虚拟析构函数带来的编译器依赖性.
7.验证RTTI的编译器依赖性.
8.验证引用计数带来的客户端的便利.
实验环境
1.Windows7专业版
2.MicrosoftVisualStudio
3.BorlandC++Builder6
实验要求
1.自行拟定组件的业务功能,但应与讲义中例程不同。
2.逐步完善其结构,记录下在此过程中客户端的症状。
(比如以屏幕截屏的方式)
3.分析原因,提出解决方法
4.记录试验过程,以及主要源代码
5.撰写实验报告.
实验步骤
1.使用VC建立一个DLL,输出一个类。
在VC客户端使用此类。
2.验证bc的客户端无法使用此类
3.以避免名字改编的方式输出一个函数以代替构造函数。
4.验证功能函数被名字改编导致无法链接
5.将功能函数改为虚函数并验证虚函数可以顺利调用
6.验证虚析构函数的编译器依赖性
7.以虚功能函数的方式来完成对象的释放工作
8.验证数据成员的存在导致升级困难。
9.验证参数入栈方向不一致所导致的错误
10.从实现类中分离出接口类。
客户端只与接口类交互。
11.接口类使用普通析构函数。
验证同种编译器产生的客户端会出现内存泄漏,验证异种编译器所产生的客户端无法链接。
12.接口类使用虚析构函数,验证同种编译器产生的客户端内存泄漏消失,验证异种编译器所产生的客户端仍然无法链接。
13.接口类进行改造,以纯虚函数的方式提供释放对象的功能。
14.验证接口类不变时,实现类可以进行任意的更新,而客户端可以无缝升级。
15.验证接口类的变化带来升级的困难。
16.使用多接口的方式对对象进行扩展,验证在同种编译器的客户端可以顺利升级。
17.验证以上情形在异种客户端无法链接。
18.以功能函数的方式编译器中性地实现接口转换,验证异种编译器方式下也可顺利升级。
19.验证一个对象的多个接口之间的紧密耦合性。
20.以引用计数的方式消除多接口的紧密耦合性。
软件下载
虚拟光驱
C++builder
vs2012
实验过程
1、打开visualstudio,选择visualC++开发设置。
然后点击“启动”。
使用vc建立一个dllFastStringDll
●Win32,名称为FastStringDll
●Win32控制台应用程序
●DLL
●导出符号。
运行一下,可以成功。
添加类FastString
●右键点击项目
●添加
●类
●C++类
●输入类名FastString
●完成
输入代码
代码如下
产生头文件:
FastString.h
class__declspec(dllexport)FastString
{char*m_psz;
public:
FastString(char*psz);
~FastString(void);
intLength(void);
intFind(char*psz);
};
新增实现文件:
FastString.cpp
#include"stdafx.h"//预编译
#include"FastString.h"
#include
FastString:
:
FastString(char*psz)
:
m_psz(newchar[strlen(psz)+1])
{strcpy_s(m_psz,strlen(psz)+1,psz);}//分配内存
FastString:
:
~FastString(void)
{delete[]m_psz;}//释放内存
intFastString:
:
Length(void){
returnstrlen(m_psz);}//计算长度
intFastString:
:
Find(char*psz)
{return0;}//省略,这不是我们讨论的重点.
选择release,再运行一下。
这时就生成了dll文件
2、在解决方案下添加一个客户端,使用vc客户端调用此类
●建立vc控制台程序VCClient
●设定项目属性-》配置属性:
●C/C++-》常规:
附加包含目录:
编辑:
新行:
$(SolutionDir)\FastStringDll这里路径要引对,要引入dll文件。
D:
\com\FastStringDll\Release
D:
\com\FastStringDll\FastStringDll
●链接器-》常规:
附加库目录:
编辑:
新行:
$(SolutionDir)$(Configuration)\
●链接器-》输入:
附加依赖项:
编辑加入:
FastStringDll.lib
●代码VCClient.cpp
#include"stdafx.h"
#include
#include"FastString.h"
usingnamespacestd;
int_tmain(intargc,_TCHAR*argv[])
{
FastString*pFS=newFastString("fdfd");
intres=pFS->Length();
cout< return0; } ●设定VCClient为启动项目 运行成功。 3.使用BC创建一个客户端BCClient ●打开bc创建一个VCLFormsApplication应用程序。 ●在VC的解决方案文件夹下新建文件夹筛选器BCClient。 ●在BCClient内对BC项目全部保存起来,再导入到VCClient里面 ●在BC窗口界面点一下button,再点一下视图,就能添加一个按钮了。 这里产生点击click处理事件。 ●在Unit1.cpp中,#include"Unit1.h"后面加入#include"FastString.h" ●运行,发现[bcc32Error]Unit1.cpp(7): E2209Unabletoopenincludefile'FastString.h' ●设定包含路径: Project-》Options–》C++Compiler–》Directories&conditional includefilesearchpath加上../FastStringDll VS2012是在属性-》配置属性-》VC++目录-》包含目录 ●编译通过 ●加入代码: : FastString*pFS=newFastString("fdfd"); ●对于以上代码提示无法链接 [ilink32Error]Error: Unresolvedexternal'FastString: : FastString(char*)'referencedfromD: \TEST\FASTSTRINGDLL\BCCLIENT\WIN32\DEBUG\UNIT1.OBJ ●View–》ProjectManager添加FastString.lib文件 链接失败提示: 无效的OMF,PossibleCOFF. [ilink32Error]Error: 'D: \TEST\FASTSTRINGDLL\DEBUG\FASTSTRINGDLL.LIB'containsinvalidOMFrecord,type0x21(possiblyCOFF) 这里是因为跨平台,所以vc下引用dll和bc下引用效果不一样。 所以如何解决这个问题呢? ●使用coff2omf工具,cmd中输入“coff2omf.exeFastStringDll.libbc.lib”进行转换。 需要先退出C盘,进入D盘lib文件所在的地方 到上一级目录,请使用cd.. 进入D盘,请使用d: 进入想要的目录,请使用cd 这里还有其他两种方法 一、使用implib命令 1、用C++Builder的implib工具生成DLL对应的lib文件。 生成lib文件之后,C++Builder便可以使用这个lib文件了。 2、在.h中用extern"C"修饰VC导出的DLL函数。 如: extern"C"__declspec(dllexport)intaFunc(inta),就可以调用了。 二、coff2omf.exe 工具程序coff2omf.exe将.lib转换为BCB可用的,然后添加进工程,直接使用VC的头文件就可以了。 三、动态调用 C/C++code //Main.h HINSTANCEhDllInst;//声明Dll句柄 int(__stdcall*sdfm)(unsignedchar,unsignedshort,long);//声明变量 C/C++code //Main.cpp void__fastcallTForm: : FormCreate(TObject*Sender) {//框架启动时初始化Dll模块,这里以DllName.dll为例 if(NULL==hDllInst) hDllInst=LoadLibrary("DllName.dll"); if(hDllInst) sdfm=(int(__stdcall*)(unsignedchar,unsignedshort,long))GetProcAddress(hDllInst,"sdfm"); } 生成的新lib文件如图: ●把bc.lib包含到项目中 ●提示构造函数无法链接。 4.在VC中,FastString输出函数CreateObject: FastString.h文件: extern"C"__declspec(dllexport)FastString*CreateObject(char*psz); FastString.cpp文件: FastString*CreateObject(char*psz) { returnnewFastString(psz); } ●重新编译,重新更新lib文件。 ●BCClient: 代码改为: FastString*pFS=CreateObject("fdfdd"); ●编译通过! ●但是如果加上: pFS->Length();//提示链接出错。 5.把Length和Find改为虚函数。 以上链接通过。 6.BC的运行过程。 ●IDE下运行无结果。 ●直接运行提示出错: 找不到DLL ●Project–》options-》C++(SharedOptions)->将Finaloutput设定为Dll所在位置: ../Debug ●代码: FastString*pFS=CreateObject("ffdfd"); intlen=pFS->Length(); ShowMessage(AnsiString(len)); 7.Length或者Find的执行情况: 执行结果不正确,将其改为_stdcall执行结果正常 8.此时可以取消对类的输出。 即服务器端删除掉__declspec(dllexport) Bc客户仍可正常执行。 9.对数据的敏感性: 客户编译器与服务器编译器同时依赖于同一个c++类定义, 在类的定义部分: 加上: Public: inta; intb; 构造函数中: a=2; b=5; 以此文件生成dll, 客户端输出: ShowMessage(AnsiString(pFS->a)); ShowMessage(AnsiString(pFS->b)); 以此文件生成客户。 得到版本1. 改变a,b的定义顺序。 生成dll和客户。 得到版本2. 打乱客户和dll的搭配关系。 A和b的值都将颠倒。 实际上是一个显示的交叉转换过程。 10.于函数也有如上特性对虚拟函数的敏感性: 定义两个虚函数: virtualintfa(); virtualintfb(); 分别实现之。 编译服务器端和客户端。 得到版本1. 改变定义顺序: virtualintfb(); virtualintfa(); 编译服务器端和客户端。 得到版本2. 打乱版本的搭配顺序,调用将出现错乱。 11.对普通函数的不敏感性: 这里客户要用同种编译器,即vc 对于以上的虚函数,改为非虚的。 打乱次序后,调用不会出错。 说明是通过名字解析的方式进行的。 12.所以要对接口进行抽象。 降低耦合性。 添加接口类: IFastString 头文件: classIFastString { public: virtualint_stdcallLength(void)=0; virtualint_stdcallFind(char*psz)=0; ~IFastString(); IFastString(); }; 实现文件: #include"stdafx.h" #include"IFastString.h" IFastString: : IFastString(void) { } IFastString: : ~IFastString(void) { } 实现类FastString.h中: #include"IFastString.h" classFastString: publicIFastString …… CreateObject的返回值改为IFastString 其声明: extern"C"__declspec(dllexport)IFastString*CreateObject(char*psz);放到接口头文件中。 客户端代码改为: #include"IFastString.h" IFastString*pFS=CreateObject("fddfd"); 13.因为接口中已经没有数据,所以自然不存在数据的敏感性。 14.在vc客户端,使用delete进行内存释放: 验证普通析构函数会出现内存泄漏。 验证方法: ⏹接口类重新向外输出__declspec(dllexport) ⏹子类分配大量内存。 IFastString*pFS=CreateObject("fdfd"); intres=pFS->Length(); deletepFS; boolb=_CrtDumpMemoryLeaks();//监控函数 cout< return0; ⏹b为1,表示有泄漏。 ⏹或者使用windows任务管理器等监控机构。 15.对以上使用虚析构函数,代码为: classIFastString { public: IFastString(void); virtual~IFastString(void); virtualint__stdcallLength(void)=0;//返回该字符串的长度 virtualint__stdcallFind(char*psz)=0;//查找指定的子串 }; 注意此时既然使用虚析构,则不用输出接口类了。 验证vc客户端内存泄漏消失。 16.验证在bc客户端,仍然对析构函数链接失败。 IFastString*pFS=CreateObject("fddfd"); intlen=pFS->Length(); deletepFS; 析构函数位置不同而产生链接失败。 17.接口改为如下形式: ●取消输出 ●增加Delete虚函数。 ●采用默认的构造和析构函数。 classIFastString { public: virtualvoid_stdcallDelete()=0; virtualint_stdcallLength(void)=0; virtualint_stdcallFind(char*psz)=0; }; delete的实现: voidFastString: : Delete() { deletethis; } 18.BC客户端改为: IFastString*pIFS=CreateObject("fdfd"); intres=pIFS->Length(); ShowMessage(AnsiString(res)); pIFS->Delete(); 通过。 19.对接口进行改变 classIFastString { public: virtualvoid_stdcallDelete()=0; virtualint_stdcallLength(void)=0; virtualint_stdcallFind(char*psz)=0; virtualint_stdcallFindN(char*psz,intn)=0; }; FastString实现新函数。 客户端对其进行调用。 生成版本2. 打乱版本1和2搭配次序。 ●老客户用新对象,正常。 ●新客户用老对象,失败。 20.增加新的接口: classIPO { public: virtualvoid_stdcallDelete()=0; virtualvoid_stdcallSave()=0; }; 多重继承: classFastString: publicIFastString,publicIPO 客户端: IPO*pIPO=dynamic_cast 验证 ●VC在接口之间可以正常运行。 IFastString*pIFS=CreateObject("fdfd"); intres=pIFS->Length(); IPO*pIPO=dynamic_cast pIPO->Save(); deletepIFS; ●BC客户端运行异常 21.中性的类型转换 接口改为如下形式: 增加dynamic函数。 classIEO { public: virtualvoid_stdcallDynamic(char*name,void**ppI)=0; virtualvoid_stdcallDelete()=0; }; classIFastString: publicIEO { public: virtualint_stdcallLength(void)=0; virtualint_stdcallFind(char*psz)=0; }; classIPO: publicIEO { public: virtualvoid_stdcallSave()=0; }; classFastString: publicIFastString,publicIPO 实现方式: voidFastString: : Dynamic(char*name,void**ppI) { if(strcmp(name,"IFastString")==0) *ppI=(IFastString*)this; elseif(strcmp(name,"IPO")==0) *ppI=(IPO*)this; elseif(strcmp(name,"IEO")==0) *ppI=(IPO*)this; } 调用方式: IPO*pIPO;IEO*pIEO; pIFS->Dynamic("IPO",(void**)&pIPO); pIPO->Dynamic("IEO",(void**)&pIEO); 22.验证多接口之间的紧密耦合性。 略。 23.引用计数。 改写接口,为以上对象添加引用计数功能 实验心得 上机课有些手忙脚乱,安装软件时也遇到各种未知问题……但一切都井然有序地进行着。 做实验最大的难题,是需要先弄懂一个关键,WHY——为什么我们要做这个实验,即这个实验的目的是什么。 弄通目标之后,接下来的实验就进行得轻松愉快了。 最重要的一句话“因为跨平台,所以VC和BC下引用DLL的效果可能不一样。 ” XX,也让我们的实验显得容易很多。 善于使用搜索引擎也是益处多多的。 比如搜索一下“C++Builder的开发指南”,就会发现很多跨平台的例子。 这个会大大帮助我们理解实验,使实验顺利地进行下去。 实验报告毕竟是份文档,如果能把实验者自己的想法、截图的方式和报告的书写,沉淀为更加规范的格式,那想必是份完美的文档。 分布式不是一门很好理解的课程,但老师能从上课、完美翻译的参考书、实验、作业等一系列方式让我们多方位地理解这门课,我们是受益匪浅的。 最后,感谢老师辛苦的授课!
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 分布式 实验 报告 127129