分布式实验报告张莹127129.docx

上传人:b****7 文档编号:9275824 上传时间:2023-02-04 格式:DOCX 页数:40 大小:2.83MB
下载 相关 举报
分布式实验报告张莹127129.docx_第1页
第1页 / 共40页
分布式实验报告张莹127129.docx_第2页
第2页 / 共40页
分布式实验报告张莹127129.docx_第3页
第3页 / 共40页
分布式实验报告张莹127129.docx_第4页
第4页 / 共40页
分布式实验报告张莹127129.docx_第5页
第5页 / 共40页
点击查看更多>>
下载资源
资源描述

分布式实验报告张莹127129.docx

《分布式实验报告张莹127129.docx》由会员分享,可在线阅读,更多相关《分布式实验报告张莹127129.docx(40页珍藏版)》请在冰豆网上搜索。

分布式实验报告张莹127129.docx

分布式实验报告张莹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(pIFS);

验证

●VC在接口之间可以正常运行。

IFastString*pIFS=CreateObject("fdfd");

intres=pIFS->Length();

IPO*pIPO=dynamic_cast(pIFS);

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的开发指南”,就会发现很多跨平台的例子。

这个会大大帮助我们理解实验,使实验顺利地进行下去。

实验报告毕竟是份文档,如果能把实验者自己的想法、截图的方式和报告的书写,沉淀为更加规范的格式,那想必是份完美的文档。

分布式不是一门很好理解的课程,但老师能从上课、完美翻译的参考书、实验、作业等一系列方式让我们多方位地理解这门课,我们是受益匪浅的。

最后,感谢老师辛苦的授课!

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 文学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1