最近,写一个程序,调用电信的web service接口,本来是个很小的项目,但是在做的过程中出现了一些问题,由于缺乏经验的问题。在此总结之。

项目虽小,但是五脏俱全。涉及了文件I/O的操作、字符编码转换、linux下c++使用web service、c++使用c#dll、网络通信和程序发布问题。

一)文件I/O

二)字符编码转换

三)linux下c++使用web service

1.安装gSoap

我使用gSOAP在Linux下调用web service,可以到:http://www.cs.fsu.edu/~engelen/soap.html下载,我使用的是gsoap_2.7.17.zip,下载下来解压缩,然后放到linux机器上。

然后安装:

# cd gsoap_2.7.17

# ./configure --prefix=/home/mengxy/gSOAP(指定安装路径)

# make

# make install

这样就安装完成了。

2.生成客户端存根程序和框架

wsdl2h.exe: 编译wsdl文件生成c/c++头文件

-o 文件名,指定输出头文件 
-n 名空间前缀 代替默认的ns 
-c 产生纯C代码,否则是C++代码 
-s 不要使用STL代码 
-t 文件名,指定type map文件,默认为typemap.dat 
-e 禁止为enum成员加上名空间前缀

soapcpp2.exe: gSOAP编译器,编译头文件生成服务器和客户端都需要的c/c++文件(默认使用STL,需要stlvector.h)

-C 仅生成客户端代码 
 -S 仅生成服务器端代码 
 -L 不要产生soapClientLib.c和soapServerLib.c文件 
 -c 产生纯C代码,否则是C++代码(与头文件有关) 
 -I 指定import路径(见上文) 
 -x 不要产生XML示例文件 
 -i 生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)

执行命令:

# cd /home/mengxy/gSOAP/bin

# ./wsdl2h -o /home/mengxy/SC_WSFORSP/wsforsp.h http://218.6.254.34/WSForSP/WSForsp.asmx?WSDL

# ./soapcpp2 /home/mengxy/SC_WSFORSP/wsforsp.h

注:其中的路径和wsdl的地址请换上你自己用到的地址。

这样生成的文件在gSoap安装路径下的bin文件夹下,在我的电脑上是/home/mengxy/gSOAP/bin。

把如下文件拷贝到你的项目:

soapStub.h,soapH.h,stdsoap2.h

soapC.cpp,soapClient.cpp,stdsoap2.cpp
soapxxSoapProxy.h
xxSoap.nsmap

其中stdsoap2.h和stdsoap2.cpp在文件夹gsoap_2.7.17中。

3.代码示例

// sc_web_service.h /* title: 使用gsoap调用四川web service接口 author: mengxy date: 2010-09-13 description: */ #ifndef __SC_WEB_SERVICE_H__ #define __SC_WEB_SERVICE_H__ typedef struct send_radius_t END_RADIUS_QUE_BODY; class SC_Web_Service_Impl; class SC_Web_Service { public: static SC_Web_Service * get_instance() { static SC_Web_Service instance; return &instance; } ~SC_Web_Service(); int send(SEND_RADIUS_QUE_BODY * body); private: SC_Web_Service(); SC_Web_Service(const SC_Web_Service &); SC_Web_Service & operator=(const SC_Web_Service &); SC_Web_Service_Impl * impl_; }; #endif // __SC_WEB_SERVICE_H__

#include "Send_Msg_Define.h" #include "sc_web_service.h" //#include "../gsoap/soapStub.h" #include "../gsoap/soapWSForSPSoapProxy.h" #include "../gsoap/WSForSPSoap.nsmap" #include <string> class SC_Web_Service_Impl { public: int send(SEND_RADIUS_QUE_BODY * body); private: WSForSPSoap ws_for_sp_; _ns1__VnetUserUseLogService usr_use_log_; _ns1__VnetUserUseLogServiceResponse usr_use_log_response_; }; int SC_Web_Service_Impl::send(SEND_RADIUS_QUE_BODY * body) { if(NULL == body) return -1; std::string usr = body->user_; std::string service_id = body->service_id_; std::string service_item_id = body->service_item_id_; std::string spid = body->spid_; std::string ip_ = body->ip_; std::string log_tm = body->log_tm_; std::string tm_stamp = body->time_stamp_; std::string authenticator = body->authenticator_; usr_use_log_.user = &usr; usr_use_log_.accounttype = body->account_type_; usr_use_log_.Serviceid = &service_id; usr_use_log_.ServiceItemid = &service_item_id; usr_use_log_.Spid = &spid; usr_use_log_.IP = &ip_; usr_use_log_.LogTime = &log_tm; usr_use_log_.TimeStamp = &tm_stamp; usr_use_log_.Authenticator = &authenticator; int rst = ws_for_sp_.__ns1__VnetUserUseLogService(&usr_use_log_, &usr_use_log_response_); if(SOAP_OK == rst) { if(-1 == usr_use_log_response_.VnetUserUseLogServiceResult->Result) { // std::cerr << "call web service failed.(" << *(usr_use_log_response_.VnetUserUseLogServiceResult->ErrorDescription) << ")/n"; return -1; } }else { return -1; } return 0; } SC_Web_Service::SC_Web_Service() : impl_(new SC_Web_Service_Impl()) { } SC_Web_Service::~SC_Web_Service() { delete impl_; } int SC_Web_Service::send(SEND_RADIUS_QUE_BODY * body) { return impl_->send(body); }

以上代码通过代理类WSForSPSoap调用了接口__ns1__VnetUserUseLogService。

4.makefile的注意点

在makefile中加入生成soapC.o、stdSoap2.o和soapClient.o的命令,链接生成程序的时候需要用这几个目标文件。

soapC.o: g++ -o $(OBJ_PATH)/soapC.o $(CPPFLAGS) $(GSOAP_SRC_PATH)/soapC.cpp stdSoap2.o: g++ -o $(OBJ_PATH)/stdSoap2.o $(CPPFLAGS) $(GSOAP_SRC_PATH)/stdsoap2.cpp soapClient.o: g++ -o $(OBJ_PATH)/soapClient.o $(CPPFLAGS) $(GSOAP_SRC_PATH)/soapClient.cpp

ok,这样就可以了。

5.乱码问题解决

在使用过程中由于调用web service得到的字符串是Utf-8编码的,造成了乱码。查了下得到的字符串也不对,命名返回了十几个中文字符,然而字符串的长度才14,这不应该,于是google了一下,做了以下修改,在soapxxSoapProxy.h中修改proxy类,在我的项目中该类为WSForSPSoap,修改其构造函数,将其中的soap = soap_new();改为soap = soap_new1(SOAP_C_UTFSTRING),这样就可以得到正确的utf-8字符串,但是却不一定能够正确显示,由于我的i18n文件中LANG="zh_CN.GB18030",所以我在程序里又使用iconv函数族将utf-8字符串转换成GB18030字符串,至此可以正确显示了。

四)c++使用c# dll

先上代码。

#include "stdafx.h" #include "PSO.h" #using "VNetPSO.dll" using namespace Microsoft::SCVNET::PSO; using namespace System; using namespace System::Runtime::InteropServices; #pragma managed #define CIPHERTEXT_MAX_LENGTH 255 //将非托管的ANSI字符串转换成托管字符串 String ^ UnmanagedStringA2ManagedString(char * pIn) { String^ strOut = Marshal::PtrToStringAnsi(static_cast<IntPtr>(pIn)); return strOut; } //将托管字符串转换成非托管的ANSI字符串 char * ManagedString2UnmanagedStringA(String ^ strIn) { IntPtr ip = Marshal::StringToHGlobalAnsi(strIn); const char* pTemp = static_cast<const char*>(ip.ToPointer()); char *pOut = new char[strlen(pTemp)+1]; strcpy(pOut, pTemp); Marshal::FreeHGlobal( ip ); return pOut; } void generateAuthenticator(char * src, char * key, char * & authenticator) { PSOCryptography ^cryptography = gcnew PSOCryptography(); String ^ t_src = UnmanagedStringA2ManagedString(src); array<unsigned char> ^ keyarr = cryptography->HexStringToByteArray(UnmanagedStringA2ManagedString(key)); array<unsigned char> ^ IV = {1, 2, 3, 4, 5, 6, 7, 8}; array<unsigned char> ^ encrpted = gcnew array<unsigned char>(CIPHERTEXT_MAX_LENGTH); cryptography->Encrypt(keyarr, IV, cryptography->ComputeHash(cryptography->ConvertStringToByteArray(t_src)), encrpted); String ^ t_auth = cryptography->ToBase64String(encrpted); authenticator = ManagedString2UnmanagedStringA(t_auth); }

注意,这是在windows下vs2005环境下用c++使用c# dll。使用c# dll需要用到c++/cli,具体语法,请自查(不过满少的资料)。项目属性要设置/clr,General->Common language Runtime Support中进行该项设置。

这里有几个注意点:

1.“未处理的异常:System.IO.FileNotFoundException...",遇到此问题,请将c# dll放到可执行程序同目录下。

2.一开始我是直接建一个项目未win32控制台程序,然后按照这种方式使用c# dll,但是有莫名其妙的错误。所以查了一下,有人建议首先创建一个使用托管的dll项目调用c# dll的接口,然后创建一个非托管的应用程序项目,使用该dll。于是,我建了一个dll,项目属性设置了/clr,建了一个win32控制台程序,项目属性未设置/clr。

五)网络通信

六)程序发布中的问题

在将加密服务器发布时出现“应用程序配置不正确,应用程序未能启动...”。然后我对它进行排查,首先把用到的dll和.manifest文件到服务器上,还是同样的错误。于是打开.manifest文件查看程序所需要的依赖,发现需要Microsoft.VC80.CRT,于是拷贝开发机器上“vs2005/SDK/v2.0/BootStrapper/Packages/vcredist_x86”下的vcredist_x86.exe到服务器上安装。(也可以到“vs2005/VC/redist/x86/Microsoft.VC80.CRT”直接拷贝下面的dll和.manifest文件到服务器上)到这里,我认为万事大吉了,然后运行,又一次出现了错误,显示“应用程序正常初始化失败”,然后我仔细想想还缺少什么文件。由于我使用了电信提供的c# dll,所以我觉得可能是服务器没有安装.NET   Framework,于是下载了Microsoft .NET Framework 2.0 版可再发行组件包(它用来安装运行针对 .NET Framework 2.0 版开发的应用程序时所需的 .NET Framework 运行库及相关文件),在服务器上进行安装,最终运行成功。

附:.manifest文件说明

缺少.manifest文件常常会造成“应用程序配置不正确,应用程序未能启动...”的问题。.manifest文件的作用是为了解决 以前windows上的“Dll 地狱” 问题而产生的新的DLL管理解决方案。大家知道,Dll是动态加载共享库,同一个Dll可能被多个程序所使用,而所谓“Dll 地狱”就是当不同程序依赖的Dll相同,但版本不同,于是造成了加载了不正确的Dll版本,造成程序出现错误。于是有了.manifest文件,它是一个程序集清单,每个程序都要有一个.manifest文件,里面列出其所需要的所有依赖。

网上有个朋友有个建议:在你的VC++安装目录下面的“.../VC/redist”目录下,有着所有发布所需要的vc库和.manifest文件。所以你想要发布一个程序最简单最安全的做法(不用担心用户电脑是否包含你所需要的库)就是把这个目录下面的相应的库的文件夹和你的可执行文件放在一起发布。

项目比较大,寻找这些依赖所需要的工作比较耗时繁琐的时候可以参照这位兄台的做法,项目比较小,将需要的依赖拷贝过去即可,没必要把该文件夹下所有东西都拷贝过去。

麻雀虽小五脏俱全--一个小项目的总结相关推荐

  1. 读pcap文件,bcp入库,一个小项目的备忘录

    数据量很大,每天几十G的pcap文件.思路是这样的:读出pcap文件中的数据,拼成字符串,写到文件里,用bcp方式入库.库是sql server. 遇到的问题: 1.读pcap文件.Pcap文件中包含 ...

  2. 麻雀虽小五脏俱全的Vue拉勾项目,看看应该有帮助

    全栈系列Vue版拉勾,客官们来瞧瞧 模拟拉勾app系列---vue前端界面 github地址,来猛戳吧 前言 本项目是本人在闲暇时间编写的一个初级引导项目,麻雀虽小五脏俱全,所使用的东西绝大多数在开发 ...

  3. 感应开关垃圾桶小项目的完成及问题解决——基于STC89C52RC单片机

    感应开关垃圾桶小项目的完成及问题解决--基于STC89C52RC单片机 分为五个步骤,如下: 01代码_舵机 注意:舵机的使用不能自己用手将其旋转,可能导致舵机的损坏(本人因此弄坏一个,或许是使用的舵 ...

  4. 麻雀虽小五脏俱全的Vue拉勾项目,看看应该有帮助 1

    全栈系列Vue版拉勾,客官们来瞧瞧 模拟拉勾app系列-vue前端界面 github地址,来猛戳吧 前言 本项目是本人在闲暇时间编写的一个初级引导项目,麻雀虽小五脏俱全,所使用的东西绝大多数在开发中都 ...

  5. 这是可用于下一个项目的React Native工具列表

    by Rajput Mehul 通过拉杰普特·梅胡尔(Rajput Mehul) 这是可用于下一个项目的React Native工具列表 (Here's a list of React Native ...

  6. 09_Android中ContentProvider和Sqllite混合操作,一个项目调用另外一个项目的ContentProvider

    1.  编写ContentPrivider提供者的Android应用 清单文件 <?xml version="1.0" encoding="utf-8"? ...

  7. 赤虹JSON模块 v1.0 麻雀虽小, 五脏俱全

    类模块公开方法 测试代码, 简洁易懂 输出结果 * "地球OL.国家成员数量" | 5 * "{"地球OL":{"国家":[&qu ...

  8. 大作坊小项目的 管理实施小总结。

    1. 项目环境的搭建 1.1 数据库环境: 新建一个"DbName_DEV"(开发)数据库,  再复制两个副本,命名为"DbName_SIT"(集成测试),&q ...

  9. 我是如何开发一个项目的

    女主宣言 我们理想中的软件工程项目的开发,就应该像电影里盖房子似的按部就班,逐期交付.然而在现实中的项目,往往会遇到各种内外部的阻力或者变动,今天咱就来聊聊我们是如何优雅避开这些坑的.本文最先发布于 ...

  10. Eclipse 下如何引用另一个项目的Java文件

    有关联的2个项目,有些类是相同的.例如实体类. 如果你采用 Ctrl + C & Ctrl + V 的方式,以后再有改动,2个项目就都需要改动. 怎样才能只改动一个呢? 答案就是,在一个项目( ...

最新文章

  1. iframe怎么用_怎么样减少无效URL的爬行和索引
  2. Msql的DML、DDL、DCL的区别
  3. 《Genesis-3D游戏引擎系列教程-进阶篇》6:动画
  4. python快速排序最简单写法_漫画:最最最最最简单的选择排序
  5. c++学习笔记之类模板
  6. IIR+全通滤波器级联实现系统零相位相移_matlab仿真
  7. MySQL 多实例详解
  8. Redis学习笔记1-Redis数据类型
  9. 网络语言不c,哪些网络用语不文明?
  10. 背景图片自适应,不重复
  11. 基于 Sentry Hive 权限控制命令详解
  12. 虚拟云服务器 网站备案,云虚拟主机可以做备案吗
  13. python21天打卡Day9-string和dict类型互转
  14. java解压缩和shell_shell 文件的归档和压缩
  15. 利用FreeType和OpenGL进行矢量字体渲染
  16. ORACLE SQL功能优化系列(一)
  17. Python爬取猫眼电影排行榜并写入MySQL
  18. 二十年后我发明了保姆机器人作文_我想发明保姆机器人作文500字
  19. 克隆的虚拟机一直重复出现登录界面_QQ空间里的装扮怎样才能克隆到自己空间?...
  20. hanoi塔栈递归算法c语言,c++递归函数,c语言递归算法经典实例

热门文章

  1. Pika 2.3.5 升级 3.0.16
  2. excel超链接无法打开服务器文件,excle链接的未打开 | excel超链接打不开,超链接后点击出现无法打开指定的文件,求高手解决...
  3. 个人网页制作(教你制作简单网页)
  4. 某一个网站打不开,其它网站都能正常打开
  5. .Net 发送邮件
  6. runtime error python 3.5_Python 3.5 RuntimeError: can't start new thread
  7. linux超时设置函数,I/O操作上设置超时之alarm闹钟法
  8. matlab筛选excel数据统计,MATLAB读取Excel筛选符合条件的数据进行求均值等处理 程序......
  9. 关于qt缺少xcb问题终极解决办法
  10. 极光短信验证码服务器,极光推送的短信验证使用