分享

WCF over JMS(ActiveMQ) 与 gSoap over JMS(ActiveMQ) 通信总结 | 学步园

 yespon 2016-10-18

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:///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:///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;

 

赋值时多采用【*指针 = *指针】的方式

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多