您的位置:首页 > 其它

WCF over JMS(ActiveMQ) 与 gSoap over JMS(ActiveMQ) 通信总结

2012-11-28 09:00 218 查看
WCF over JMS 与 gSoap over JMS 通信总结
一共有三个项目:

项目1:WCFServiceLibrary 定义接口

项目2:C++的Server

项目3:C#的Client

步骤一:定义接口(项目1)

把项目2调用项目3的接口和项目3调用项目2的接口都集成到项目1里,接口可以为Request/Response模式和OneWay模式,接口实现为空,BasicHttpBinding

步骤二:项目2使用接口

1、在某个文件夹下放入gSoap包内的三个文件wsdl2h.exe,soapcpp2.exe,typemap.dat和三个文件夹import,extras,custom

2、运行项目1,获取wsdl地址,用gSoap提供的工具wsdl2h.exe生成接口头文件gSoap.h

cmd: wsdl2h.exe -o gSoap.h http://localhost:6666/Interface/Service/?wsdl
3、用gSoap提供的工具soapcpp2.exe生成C++需要的代理文件

cmd: soapcpp2.exe -1 -i -x -a -IimportgSoap.h

-1 代表使用SOAP1.1协议,-i代表生成C++代理类,-x代表不生成xml文件,-a代表加入action检查,-Iimport代表使用import文件夹内的文件,其中import中的文件又会牵扯到另两个文件夹

4、删除gSoap.h文件。

第2到4步可以用一个bat文件代替,bat文件存放在当前文件夹,内容为:

echo off

wsdl2h.exe -o gSoap.hhttp://localhost:6666/Interface/Service/?wsdl

soapcpp2.exe -1 -i -x -a -Iimport gSoap.h

del gSoap.h

Pause

5、双击bat文件生成soapH.h、soapC.cpp、soapStub.h、-.nsmap、-Proxy.h、-Proxy.cpp、-Service.h、-Service.cpp共八个文件。把这八个文件放到项目2的一个gSoap文件夹下,并把gSoap包提供的stdsoap2.h、stdsoap2.cpp、duration.h、duration.cpp也放到此文件夹内

6、修改stdsoap2.cpp文件,添加宏(若不添加此宏,链接时会出错,算是gSoap的bug):

#ifndef WITH_NONAMESPACES

#define WITH_NONAMESPACES

#endif

7、修改duration.cpp文件,此文件中只有xsd系列的5个函数,仿照着写出ns3系列的函数。这应该是gSoap的一个bug,如果不实现这五个函数,链接会出错

8、修改-Proxy.h、-Proxy.cpp文件。删除本项目作为服务端的代码

9、修改-Service.h、-Service.cpp文件。删除本项目作为客户端的代码。实现其他接口

10、项目2引入此文件夹及这12个文件,即可实现Http通信功能。

11、实现over JMS功能。加入JMS封装类QueueProducer、QueueConsumer、TopicProducer。在-Proxy.cpp、-Service.cpp文件中,把通信底层换成JMS。

Service端函数:

static int serve___ns1__Fun(BasicHttpBinding_USCOREIServiceService*soap)

{ struct__ns1__Fun soap_tmp___ns1__Fun;

_ns1__FunResponsens1__FunResponse;

ns1__FunResponse.soap_default(soap);

soap_default___ns1__Fun(soap,&soap_tmp___ns1__Fun);

soap->encodingStyle= NULL;

if(!soap_get___ns1__Fun(soap, &soap_tmp___ns1__Fun, "-ns1:Fun",NULL))

return soap->error;

if(soap_body_end_in(soap)

|| soap_envelope_end_in(soap)

|| soap_end_recv(soap))

{/*returnsoap->error;*/}

soap->error= soap->Fun(soap_tmp___ns1__Fun.ns1__Fun, &ns1__FunResponse);

soap->action= "http://tempuri.org/IService/FunResponse";

soap->mode= 1;

soap->bufidx= 0;

soap->ns= 0;

memset(soap->buf,0, 65536);

if(soap_envelope_begin_out(soap)

|| soap_putheader(soap)

|| soap_body_begin_out(soap)

|| ns1__FunResponse.soap_put(soap,"ns1:FunResponse", "")

|| soap_body_end_out(soap)

|| soap_envelope_end_out(soap))

return soap->error;

soap->buflen= soap->bufidx;

return0;

}

Proxy端函数:

int BasicHttpBinding_USCOREIServiceProxy::Fun(constchar *endpoint, const char *soap_action, _ns1__Fun *ns1__Fun, _ns1__FunResponse*ns1__FunResponse)

{

structsoap *soap = this;

struct__ns1__Fun soap_tmp___ns1__Fun;

soap_tmp___ns1__Fun.ns1__Fun= ns1__Fun;

soap->action= "http://tempuri.org/IService/Fun";

memset(soap->buf,0, 65536);

soap->mode= 1; // 消息添加进buf中而不是显示在屏幕上

soap->ns= 0; // 添加头

soap->bufidx= 0;

if(soap_envelope_begin_out(soap)

|| soap_putheader(soap)

|| soap_body_begin_out(soap)

|| soap_put___ns1__Fun(soap,&soap_tmp___ns1__Fun, "-ns1:Fun", NULL)

|| soap_body_end_out(soap)

|| soap_envelope_end_out(soap))

return soap->error;

// 发送消息并接收响应

stringqstrSendMSG = string(soap->buf, soap->bufidx);

stringqstrReturnMSG;

m_pQueueProducer->SendQueueMessage(qstrSendMSG,qstrReturnMSG);

if(qstrReturnMSG.empty())

{

return 0;

}

intnLength = qstrReturnMSG.length();

strncpy(soap->buf,qstrReturnMSG.c_str(), nLength);

soap->bufidx= 0;

soap->buflen= nLength;

soap->mode= 0;

soap->peeked= 0;

soap->ahead= 0;

if(soap_envelope_begin_in(soap)

|| soap_recv_header(soap)

|| soap_body_begin_in(soap))

return soap->error;

ns1__FunResponse->soap_get(soap,"ns1:FunResponse", "");

return0;

}

12、-Service类中加入一个函数disposeBuf,当接收到JMS消息时,把消息内容复制到soap->buf中,然后进行dispatch(),决定到底使用哪个接口

void QueueConsumer::onMessage( const Message* message) throw() {

try

{

const TextMessage* textMessage =

dynamic_cast<const TextMessage* >( message );

std::string text = "";

if( textMessage != NULL )

{

text= textMessage->getText().c_str();

if(text.empty()) return;

}

m_pService->disposeBuf(text);

std::string qstrReplyMSG =std::string(m_pService->buf, m_pService->buflen);

...

//d add {

voidBasicHttpBinding_USCOREIServiceService::disposeBuf(std::string strMSG)

{

intnLength = strlen(strMSG.c_str());

memset(this->buf,0, 65536);

strncpy(this->buf,strMSG.c_str(), nLength);

this->buflen= nLength;

this->bufidx= 0;

soap_envelope_begin_in(this);

soap_recv_header(this);// 删除此句没影响

soap_body_begin_in(this);

dispatch();

}

//d add }

13、修改soapC.cpp,在soap_out_SOAP_ENV__Header()、soap_in_SOAP_ENV__Header()两个函数中加入处理action的代码

SOAP_FMAC3 int SOAP_FMAC4soap_out_SOAP_ENV__Header(struct soap *soap, const char *tag, int id, conststruct SOAP_ENV__Header *a, const char *type)

{

(void)soap;(void)tag; (void)id; (void)type;

if(soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, a,SOAP_TYPE_SOAP_ENV__Header), type))

return soap->error;

//d add{

if(soap_element_begin_out(soap, "Actionxmlns=\"http://schemas.microsoft.com/ws/2005/05/addressing/none\"",id, type)

|| soap_string_out(soap,soap->action, 0)

|| soap_element_end_out(soap,"Action"))

return soap->error;

//d add}

returnsoap_element_end_out(soap, tag);

}

SOAP_FMAC3 struct SOAP_ENV__Header * SOAP_FMAC4 soap_in_SOAP_ENV__Header(structsoap *soap, const char *tag, struct SOAP_ENV__Header *a, const char *type)

{

if(soap_element_begin_in(soap, tag, 0, type))

return NULL;

//d add{

soap_in_string(soap,"Action", &soap->action, "xsd:string");

//d add}

...

14、在使用客户端时,让soap->header不为空,则可以加上header和action

m_pProxy = newBasicHttpBinding_USCOREIServiceProxy(SOAP_C_UTFSTRING);

m_pProxy->header = new struct SOAP_ENV__Header();

步骤三:项目3使用接口

1、修改项目1,使项目1仅具有项目3作为客户端时的接口

2、项目3引用项目1的服务,此时,项目3具备了作为客户端的功能

3、修改项目1,使项目1仅具有项目3作为服务端时的接口

4、项目3获得项目1的IService.cs,Service.cs两个文件,并把项目1的app.config文件合并进项目3,此时,项目3具备了作为服务端的功能

5、实现over JMS,略。

步骤四:接口规则

1、项目1定义接口时,参数可以使用C#普通类型(int、char、double、float、string)、结构体、List

2、C#端定义string,可以用string str = ""; 不要用string str = null;

3、String类型赋值时要Base64 encode,得到时要Base64 decode

4、C++端接口如果是Request/Response模式,则有两个结构体参数,第一个是输入参数,第二个是输出参数;如果是OneWay模式,则有一个结构体参数。

5、C++端-Service类接口实现时,由于结构体参数内部大部分都为指针,而且如果用对象给输出参数赋值的话,经常会出现对象销毁而打包失败,故采取以下措施:

intBasicHttpBinding_USCOREIService1Service::ClientLogin(_ns1__ClientLogin *ns1__ClientLogin,_ns1__ClientLoginResponse *ns1__ClientLoginResponse)

{

// 防止多次泄露,这样只泄露一次的内存空间

static_ns1__ClientLoginResponse* pClientLoginResponse = NULL;

if(pClientLoginResponse != NULL)

{

deletepClientLoginResponse->ClientLoginResult;

pClientLoginResponse->ClientLoginResult = NULL;

deletepClientLoginResponse->error;

pClientLoginResponse->error = NULL;

deletepClientLoginResponse->sessionId;

pClientLoginResponse->sessionId = NULL;

delete pClientLoginResponse;

pClientLoginResponse = NULL;

}

pClientLoginResponse = new _ns1__ClientLoginResponse();

pClientLoginResponse->ClientLoginResult = new bool;

pClientLoginResponse->error = new string;

pClientLoginResponse->sessionId = new string;

// 防止多次泄露处理完毕

...

*ns1__ClientLoginResponse =*pClientLoginResponse;

赋值时多采用【*指针 = *指针】的方式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: