Chinaunix首页 | 论坛 | 博客
  • 博客访问: 590498
  • 博文数量: 226
  • 博客积分: 10080
  • 博客等级: 上将
  • 技术积分: 1725
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-26 11:15
文章分类

全部博文(226)

文章存档

2011年(5)

2010年(64)

2009年(99)

2008年(37)

2007年(21)

我的朋友

分类: C/C++

2007-11-26 19:23:09

gSOAP是一个开源的项目,用它可以方便的使用c/c++地进行SOAP客户端和服务器端编程,而不必了解xmlSOAP协议的细节。这样使用者就可以专注于自己的web service 客户端或服务器端的编写,而不用纠缠与其它细节。我第一次接触这些东西,我对SOAP的理解是这样的:以http协议为基本的通信协议,以xml文件形式请求远程服务,再以xml文件的形式返回执行结果,我理解的就这么简单了,有啥不妥处,还请指教阿。

 

      实践一下才有理性认识,下面是我自己在windows下,具体说来就是用vc 6.0下编写的一个很简单的客户端程序调用远程的服务,来发送电子邮件,感觉很爽吧。 

        首先我们到下载gSOAP下载工具集吧,不同的系统下用的gSOAP是不一样的,根据需要下载了windows下的和linux下的。gSOAP工具集不需要安装,直接解压就可以了。在bin目录下我们可以看到两个可执行文件:

            soapcpp2.exe: gSOAP编译器,编译头文件生成服务器和客户端都需要的 c/c++文件。
            wsdl2h.exe: 编译wsdl文件生成c/c++头文件。

        其次,我们到下载wsdl文件,假设保存文件名为:AbysalEmail.wsdl。所谓的wsdl文件翻译成中文就是网络服务描述文件了。我们用wsdl2h.exe工具来根据wsdl文件生成c/c++头文件,可以用-c选项是生成纯c的头文件,另外用-s选项是说明我们在程序中不使用stl,注意了默认我们是适用stl的。

        用如下命令:
       
            wsdl2h  -o AbysalEmail.h AbysalEmail.wsdl

        说明:
            既可以生成我们需要的AbysalEmail.h头文件了。这里文件名可以随便起了。将下载的gsoap的import里的stlvector.h中文件拷贝到当前的文件夹下,因为默认是使用stl的,所以需要它。然后执行soapcpp2 命令来生成存根程序.

        用如下命令:

            soapcpp2  -C AbysalEmail.h

        说明:

            -C  选项是只生成客户端的,默认是生成客户端和服务器端的,如果你在程序中使用了vector还要加上 –limport选项。即可以生存客户端存根程序和框架了。

        soapClient.cpp:编译客户端的需要的存根例程。
        soapC.cpp,soapH.h:用来序列化和反序列化c/c++不同数据类型。
        soapServer.cpp: 编译服务器端的需要的存根例程。
        soapXXXProxy.h: 生成的代理类的头文件,使用代理类时需要此文件。

        本程序为soapSendEmailBindingProxy.h。

        第三步,就是在vc中建个工程,设置如下:

        在vc6中建立工程,其源文件为:sendMailClient.cpp soapC.cpp
                                     soapClient.cpp   stdsoap2.cpp

        头文件为:      AbysalEmail.h soapH.h soapStub.h stdsoap2.h     
       
        其他依赖文件为:basetsd.h  sendemailbinding.nsmp stdsoap2.cpp stdsoap2.h是下载的gSOAP中包含的。

        另外在所需要的库中把wsock32.lib加上,gSOAP也是采用socket方式连接的。其中sendMailClient.cpp为我写的客户端程序,程序如下:

#include "soapH.h"                                      // 得到存根程序
#include "SendEmailBinding.nsmap"            //得到名称空间映射表 
#include "soapSendEmailBindingProxy.h"
 

using namespace std;

int main(int argc, char **argv)
{
    struct soap email_soap;
    int result = -1;
    SendEmailBinding  EmailBind;              //生成代理类对象
    _ns1__SendEmail  sendEmail;              //web服务发送电子邮件对象
   _ns1__SendEmailResponse  Email_Response;  //web 服务返回发送结果对象
   string from = "mseaspring";
   string to   = "David";
   string sub = "Hello test!";
   sendEmail.From = &from;
   sendEmail.FromAddress = "
mseaspring@hotmail.com ";
   sendEmail.MsgBody = "I want to test a web service!";
   sendEmail.To = &to;
   sendEmail.ToAddress = "
mseaspring@gmail.com ";
   sendEmail.Subject = ⊂

   result = EmailBind.__ns1__SendEmail(&sendEmail,  &Email_Response);
    if (result != 0)
    {
                printf("soap error ,errcode = %d ", result);
     }
     else
     {
               cout<<"恭喜你,邮件发送成功!"<

      }
        return 0;
}

    我程序中是采用代理类的方式编写的程序,不用代理类的代码如下:

#include "soapH.h"                                    //  得到存根程序
#include "SendEmailBinding.nsmap"            // 得到名称空间映射表

using namespace std;

int main(int argc, char **argv)
{
    struct soap email_soap;
    //初始化gSoap运行时环境变量,只需初始化一次
    soap_init(&email_soap);
   int result = -1;
   //远程web服务的endpoint URL
   const char* server="
";
   string from = "mseaspring";
   string to   = "David";
   string sub = "Hello test!";
   sendEmail.From = &from;
   sendEmail.FromAddress = "
mseaspring@hotmail.com ";
   sendEmail.MsgBody = "I want to test a web service!";
   sendEmail.To = &to;
   sendEmail.ToAddress = "
mseaspring@gmail.com ";
   sendEmail.Subject = &sub
    //调用根据远程服务产生函数的接口
   result = soap_call___ns1__SendEmail(&email_soap, server, "", &sendEmail,  &Email_Response);
    if(email_soap.error)
     {
                //在stderr流中打印soap的错误信息
                soap_print_fault(&email_soap,stderr);
                result = email_soap.error;
        }
        soap_destroy(&email_soap);// 删除反序列化类的实例,仅用于c++
        soap_end(&email_soap);    // 清空已经并行化的数据
        soap_done(&email_soap);   // 与gSOAP 环境相分离,关闭连接
        if (result != 0)
        {
                printf("soap error ,errcode = %d ", result);
        }
        else
        {
            cout<<"恭喜你,邮件发送成功!"<

          }
        return 0;
}
       
        你可能会问我怎么知道远程服务的接口阿? 到soapStub.h中去找就可以了,至于代理类的使用,到代理类头文件中一看便知。

        好了,终于要写完了,当然我们不仅可以编写客户端也可以编写服务器端程序,至于服务器端,有兴趣的可以自己看看gSOAP里面的文档,也很简单的,不过也要花点时间学习的了,呵呵。

        如果对于上面程序,有谁没调试成功联系我,邮箱都写在程序里那。呵呵。

        这是我很久以前写的文章了,后来我也用gSOAP写了服务器端和客户端的程序,发现一个很严重的问题,就是gSOAP客户端得到的结果中文显示不出来,后来我找了大量资料,后来终于发现原来gSOAP可以设置编码的,设置方法很简单就是 soap_set_mode(&soap, SOAP_C_UTFSTRING);

        soap 是struct soap类型,这样得到的结果就是UTF8类型,再进行转换成中文格式gbk,就可以解决了.

        还有一个问题就是编译的时候有时候会报map错误,我找不到解决方法,一气直接注释掉了那两个出错函数,居然也可以.

阅读(8670) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-03-14 11:06:51

不错。谢了

spyy262245742008-10-23 16:19:35

你好!我在windows下用qt4做了一个服务器程序QTcpServer,程序已经实现和客户端连接并能进行通信。接下来要实现的功能是:当客户端传来一个条形码BarCode,QTcpServer对该条形码进行提取并封装为SOAP消息通过HTTP协议经网络远程过程调用(RPC)数据库的商品信息,远程数据库提取SOAP消息中的条形码并到数据库中查找给条形码对应的商品信息并最终查询结果封装为SOAP消息返回给QTcpServer应用程序,QTcpServer将返回结果进行解释,并最终将条形码对应的商品信息返回给客户端。 现在遇到的问题是:如何根据远程数据库给的WSDL和XSD文件生成调用的函数。 即如何写QT4下“sendMailClient.cpp”这个文件呢?谢谢。