当前位置: 首页 > 编程日记 > 正文

gsoap使用总结

WebService、soap、gsoap基本概念

WebService服务基本概念:就是一个应用程序,它向外界暴露出一个可以通过web进行调用的API,是分布式的服务组件。本质上就是要以标准的形式实现企业内外各个不同服务系统之间的互调和集成。

soap概念:简单对象访问协议,是一种轻量的、简单的、基于 XML 的协议,它被设计成在WEB 上交换结构化的和固化的信息。

从这里的概念可以看得出来,soap是一个基于xml格式的web交互协议,而webservice是一种使用web方式实现的功能。就好像是网络视频服务器和http的关系,就是这里的webservice服务器和soap的关系。其实从历史上来说,先有的soap这种协议,然后微软用基于这种协议制作了webservice这种服务。

gsoap概念:是一种能够把C/C++语言的接口转换成基于soap协议的webservice服务的工具。

gSOAP简介

gSOAP是一个开发SOAP和XML应用(它们组成了webservice)的工具,在英文中叫toolkit。它是跨平台的,webservice的客户端和服务器端,都可以用它来辅助开发。它主要的功能(特征)如下:

  • C/C++数据绑定工具,支持XML-RPCfrom/to JSON from/to C/C++ serialization
  • 支持WSDL 1.1,2.0, SOAP 1.1, 1.2
  • 支持REST HTTP(S) 1.0/1.1 operations (GET,PUT,POST etc) for XML, JSON,etc
  • 支持MIME and MTOM 附件
  • 支持IPv4,IPv6, TCP 和UDP
  • 支持CGI,FastCGI
  • 支持嵌入到Apache,IIS中发布
  • 自带了一个Web server (multithreaded, SSL, compression)用于发布
  • 可适用于WinCE, Palm, Symbian, VxWorks, Andriod, iPhone等小设备
  • ...(拣主要的,其余忽略)

gsoap下载地址

http://sourceforge.net/project/showfiles.php?group_id=52781

gSOAP结构

目前gSOAP的版本是2.8.12,作者认为,gSOAP的组织结构以及使用的方便性,在开源项目中是比较好的。

在应用中,我们首先要应用它的两个工具: soapcpp2和 wsdl2h。所幸的是这个两个工具在gSOAP包中已经被编译生成(bin目录下),所以我们只要拿来用即可,gSOAP使用的方便性就体现出来了。另一个方便性是它的源文件个数较少,如果我们不去研究,少的文件个数包含在我们的工程中,也减少了维护的成本。

1.soapcpp2的用法

Soapcpp2是一个根据.h文件生成若干支持webservice的代码生成工具,生成的代码文件包括webservice客户端和服务器的实现框架,XML数据绑定等,具体说明如下:

文件

描述

soapStub.h

根据输入的.h文件生成的数据定义文件,一般我们不直接引用它。

soapH.h

soapC.cpp

客户端和服务器端应包含该头文件,它包含了soapStub.h。针对soapStub.h中的数据类型,cpp文件实现了序列化、反序列化方法。

soapXYZProxy.h

soapXYZProxy.cpp

这两个文件用于客户端,是客户端调用webservice的框架文件,我们的代码主要在此实现或从它继承。

soapXYZService.h

soapXYZService.cpp

这两个文件用于服务器端,是服务器端实现webservice的框架文件,我们的代码主要在此实现或从它继承。

.xsd

传输消息的schema,,我们可以看看是否满足我们的协议格式(如果有此要求)

.wsdl

这个就不用说了。

.xml

满足webservice定义的例子message,即实际的传输消息,我们可以看看是否满足我们的协议格式(如果有此要求)。

.nsmap

命名空间的定义,对命名空间不敏感的,不用关注。

使用soapcpp2时,可选项如下:

选项

描述

-1

Soap1.1绑定

-2

SOAP1.2绑定

-C

只生成客户端代码

-S

只生成服务器端代码

-T

生成自动测试代码

-L

不生成 soapClientLib/soapServerLib

-a

用 SOAPAction 和WS-Addressing调用服务器端方法

-A

用 SOAPAction 调用服务器端方法

-b

采用char[N]这样的方式来表示string

-c

生成的是C代码,不是C++代码

-d < path >

将代码生成在 < path >下

-e

生成 SOAP RPC 样式的绑定

-f N

File split of N XML serializer implementations per file

-h

显示一个简要的用法信息

-i

生成的服务代理类和对象从struct soap继承而来

-j

生成的服务代理类和对象包含struct soap而来(C代码的唯一选择)

-I < path >

包含其他文件时使用,指明 < path > (多个的话,用`:'分割),相当于#import ,该路径一般是gSOAP目录下的import目录,该目录下有一堆文件供soapcpp2生成代码时使用。

-n

用于生成支持多个客户端和服务器端(具体内容参考gSOAP文档)

-p < name >

生成的文件前缀采用< name > ,而不是缺省的 "soap"

-q < name >

C++代码中,所有声明的命名空间

-s

生成的代码在反序列化时,严格检查XML的有效性

-t

生成的代码在发送消息时,采用xsi:type方式

-u

在 WSDL/schema 输出文件中不产生XML注释

-v

显示版本信息

-w

不生成 WSDL 和 schema 文件

-x

不生成 XML 形式的传输消息文件

-y

在XML 形式的传输消息文件中,包含 C/C++类型信息



2. wsdl2h的用法

该工具是可以根据输入的wsdl或XSD或URL,产生相应的C/C++形式的.h(不能直接引用),供soapcpp2使用。

wsdl2h主要的运行选项如下:

选项

描述

-a

对匿名类型,产生基于顺序号的结构体名称

-c

生成C代码

-f

对schema扩展,产生flat C++类

-g

产生全局的元素声明

-h

显示帮助信息

-I path

包含文件时指明路径,相当于#import

-j

不产生 SOAP_ENV__Header 和SOAP_ENV__Detail 定义

-k

不产生 SOAP_ENV__Header mustUnderstand qualifiers

-l

在输出中包含license信息

-m

用 xsd.h 模块来引入类型信息

-N name

name 来指定服务命名空间的前缀。

-n name

name 作为命名空间的前缀,取代缺省的ns

-o file

输出文件名

-q name

所有的声明采用 name 作命名空间

-s

不产生 STL代码 (即不用 std::string,std::vector)

-t file

使用自己指定的type map file而不是缺省的typemap.dat

-u

不生成 unions

-v

产生详细的输出信息

-w

always wrap response parameters in a response struct

-y

为structs,enums产生 typedef定义

-_

不产生 _USCORE (用UNICODE _x005f代替)

-?

显示帮助信息

用gsoap开发web service的大致思路

我们开发webservice应用,大致有两个方向:

1.  API接口固定,不关心底层的通讯,将SOAP作为应用层协议

此时,我们先定义接口,编写好.h文件,运行soapcpp2生成出相应的代码,对服务器端,修改XXXService文件,实现业务逻辑,对客户端,修改XXXProxy文件,实现业务逻辑。

2.  通讯协议固定(当然需要基于XML的)或只有wsdl,将SOAP作为“传输层”协议

此时,我们必须根据通讯协议或wsdl生成相应的C/C++类型的.h文件,如果需要我们自己编写wsdl,则需要一点其相关知识,不过我们可以用C#等生成一个简单的wsdl,照猫画虎即可。运用wsdl2h,我们可以生成.h文件,有了.h后,按上面的步骤继续。

接口定义

可参考《GSoap接口定义》。这里我将给出C#引用这个webserver所对应的接口形式。
gsoap是根据我们定义好的.h文件,然后用工具产生了我们所需的.c文件。所以我们必须根据gsoap的要求编写.h。
1. 单个参数的传出:
int ns__add( int a, int b, int *c );
需要说明的是,这里的ns__是必须的,必须以开始注释中的ns加两个下划线开始。返回值必须是int。
但是这里的int并不是接口的返回值,而是gsoap内部的返回值。真正的返回值是int *c。

C#中对应的接口: int add( int a, int b );返回值就是上述的int *c参数。

2. 多个参数传出,在接口中必须使用结构体
typedef char * xsd__string;
typedef long xsd__int;
struct ns__personResponse{
xsd__int age;
xsd__string name;
xsd__string address;
};
int ns__person( xsd__string buf_in, struct ns__personResponse * buf_out );

在C#中,并不是我们所声明的这样。而是:int person( string buf_in, out string name, out string address);
即,结构体中的第一个域会变成返回值,其他的变成一个个的输出参数。

3. 返回结构体。如果要返回结构图,那么必须在结构体中再套一层结构体:
typedef char * xsd__string;
typedef long xsd__int;
struct ns__person{
xsd__int age;
xsd__string name;
xsd__string address;
};
struct ns__personResponse{
xsd__int ret;
struct ns__person person;
};
int ns__person( xsd__string buf_in, struct ns__personResponse * buf_out );

那么在C#中,看到的接口是这样的:int person( string buf_in, person对应的结构类 );

4. 接口中的下划线,如果接口中的交易名有下划线,必须这么声明:
int ns__echo_USCOREreverse( char * buf_in, char ** buf_out );

那么,C#中实际上的接口名就是:string echo_reverse( string buf_in );

注意事项

gsoap传输中文

使用utf-8编码格式来支持汉字的传输。
1. 设置gsoap为utf-8传输数据
soap_set_mode( &SmsWBS_soap, SOAP_C_UTFSTRING ); //设置编码
SmsWBS_soap.mode|=SOAP_C_UTFSTRING;

2. 使用下面得函数转换我们的传输内容,即将我们的数据转成UTF-8编码:
int conv_charset( const char *dest, const char *src, char *input, size_t ilen,char *output, size_t olen )
{
int convlen = olen;
iconv_t conv = iconv_open( dest, src );
if( conv == (iconv_t) -1 )
return -1;

memset( output, 0, olen );
if( iconv( conv, &input, &ilen, &output, &olen ) ){
iconv_close(conv);
return -1;
}

iconv_close(conv);
return convlen-olen;
}
例子: conv_charset( "UTF-8", "GBK", "林学任.linxr", strlen("林学任.linxr"), buf_out->name,100 );

//编码转换函数int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen)
{
iconv_t cd;
int rc;
char **pin = &inbuf;
char **pout = &outbuf;

cd = iconv_open(to_charset,from_charset);
if (cd==0) return -1;
memset(outbuf,0,outlen);
if (iconv(cd,pin,&inlen,pout,&outlen)==-1) return -1;
iconv_close(cd);
return 0;
}
//UNICODE 2 GB2312
int u2g(char *inbuf,int inlen,char *outbuf,int outlen)
{
return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}
//GB2312 2 UNICODE 
int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{
return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}

内存管理

C/C++最大的麻烦,也是最大的优点是它要求用户自己管理内存。我们在实现web service方式时,同样需要考虑内存的分配与释放。

分配内存有两类:

  • 分配n个字节,采用

void*soap_malloc(struct soap *soap, size_tn)

  • 分配某个类,采用

Class*soap_new_Class(struct soap*soap)   一个类

Class*soap_new_Class(struct soap *soap, intn)    n个类

这里的类是通讯xml中定义的元素,在response构造时,必然要创建若干此类元素。为简化类的创建,可定义如下宏:

#defineNEW_ELEMENT(classtype)     soap_new_##classtype(GetSoapStruct(),-1)

#defineNEW_ELEMENT_X(classtype,n) soap_new_##classtype(GetSoapStruct(),n)

其中 GetSoapSturct()是返回继承的或包含的structsoap结构,对继承方式的代码,它的定义如下:

struct soap *GetSoapStruct() { return(struct soap*)this; }

在我们的Web方法实现中,可以随意使用上面的new方法,在每次web方法完结后,调用soap_destroy(structsoap *soap) ,它会为我们清除掉这部分内存。

gsoap中有若干释放内存的方法,几个有用的函数(还有其它的,忽略)及其说明如下:

Function Call

Description

soap_destroy(struct soap *soap)

释放所有动态分配的C++类,必须在soap_end()之前调用。

soap_end(struct soap *soap)

释放所有存储临时数据和反序列化数据中除类之外的空间(soap_malloc的数据也属于反序列化数据)。

soap_done(struct soap *soap)

Detach soap结构(即初始化化soap结构)

soap_free(struct soap *soap)

Detach 且释放soap结构

上表中,动态分配的C++类,指上面用"soap_new"分配的类;临时数据是指那些在序列化/反序列化过程中创建的例如hash表等用来帮助解析、跟踪xml的数据;反序列化数据是指在接收soap过程中产生的用malloc和new分配空间存储的数据。在gsoap中,纯数据空间与类空间管理不同,采用两个方法,可以保留soap的反序列化数据(这时你需要自己释放)。

gsoap输出


为提升服务性能,减少数据传输量,建议所有输出都采用字符方式的xml(UTF-8),不要采用结构或对象输出(输入可以),采用结构或对象输出优点是在客户端无需解析,自动生成相关对象和结构,但是会导致服务性能下降和传输的数量增大.例如:
int ns2__login(xsd__string username,xsd__stringpassword,xsd__string &rsp);
rsp为字符串格式的xml,在客户端需要解析后方可使用.我自己定义的rsp有三种输出格式,所有节点名称都大写,所有属性名称都小写,节点之间无换行,客户端按下面的三种规则编写解析器即可.
第一种为服务器异常消息
<DATA>
<ERROR val="服务器异常消息"/>
</DATA>


第二种为正常输入
<DATA>
<ROWS>
<ROW v0="字段0的值" v1="字段1的值" vn="字段n的值"/>
更多ROW....................................... 
</ROWS>
更多ROWS....................................... 
</DATA>


第三种为字段描述信息
<DATA>
<FIELDS>
<FIELD  name="字段名称" alias="字段描述信息" type=""size="" required=""/>
更多字段描述信息.......................................
</ FIELDS >
更多FIELDS.......................................
</DATA>
type,size, required均为数字,type可以自己定义,解析时按自定义规则转换数据即可,size为字段大小, required值一般为0和1,为0表示不是必填,否则为必填项.
字符转换为保证可移值性,可采用iconv转换,windows和linux均支持,windows需要自己下载LibIconv for Windows -GnuWin32库.只需要记住UTF-8单个字符最多使用4字节存储即可.转换时一次性分配 tcslen(szBuffer) * 4 + sizeof(TCHAR)大小的内存.

webserver发布

1.    在C#中,可以直接引用一个webserver,但是我们写得webserver如何能用被其引用呢。其实只要实现gsoap的fget回调函数即可:
SmsWBS_soap.fget = http_get;
2. http_get函数实现
int http_get(struct soap * soap)
{
FILE *fd = NULL;

char *s = strchr( soap->path, '?' );
if( !s || strcmp( s, "?wsdl" ) ){
return SOAP_GET_METHOD;
}

fd = fopen( "SmsWBS.wsdl", "rb" );
if (!fd){
return 404;
}

soap->http_content = "text/xml";
soap_response(soap, SOAP_FILE);
for (;;){
size_t r = fread(soap->tmpbuf, 1, sizeof(soap->tmpbuf), fd);
if( !r ){
break;
}
if( soap_send_raw( soap, soap->tmpbuf, r) ){
break;
}
}

fclose(fd);
soap_end_send(soap);

return SOAP_OK;
}

这个具体参见文章:https://www.cnblogs.com/liushui-sky/p/9723385.html

CGI方式执行

server端可以编译成CGI方式执行,而并不是绑定到某个端口,这种方式我没有实践。

if (argc < 2)// no args: assume this is a CGIapplication
{
soap_serve(&soap); // serve request, one thread, CGI style
soap_destroy(&soap); // dealloc C++ data
soap_end(&soap); // dealloc data and clean up
}

gsoap上层缓冲区大小设置

通过更改在stdsoap2.h文件中 SOAP_BUFLEN 宏,增加缓存大小,默认缓存大小为65536

实现高性能gsoap服务

代码请参看gSOAP 2.8.14 User Guide中的7.2.4  How to Create aMulti-Threaded Stand-Alone Service.
    listen : 监听soap_accept方法,返回一个SOAP_SOCKET,然后交SOAP_SOCKET添加到队列,并发送一个信号通知process(处理线程)处理. 
process(处理线程)启动后立即阻塞等待信号,收到信号后才执行相应的任务(soap_serve
),执行任务后继续阻塞等待信号.注意:soap_serve方法如果客户端提交的xml文档格式不正确或其它数据(恶意攻击)时会一直阻塞到下一个请求,导致服务器性能严重下降,客户端无法收到数据一直等待的情况,因此在初始化处理线程的soap成功后,应该立即设置处理线程soap的超时时间,单位为秒:
soap_thr[i] = soap_copy(&soap);//在这一行示例代码后一加下面三行代码
soap_thr[i] ->send_timeout = 1;
soap_thr[i] ->recv_timeout = 1;
soap_set_mode(soap_thr[i], SOAP_C_UTFSTRING); /*设置采用UTF-8字符编码*/

gSOAP写服务器端程序

http://blog.csdn.net/mseaspring/article/details/1713283

gSOAP写服务器端程序,现在将gSOAP文档中的算术服务器的程序与文档中的多线程服务器结合,写了个多线程算术服务器。

一 gSOAP需要的头文件:

//gsoap ns servicename: calc
//gsoap ns service style: rpc
//gsoap ns service encoding: encoded
//gsoap ns service namespace: http://127.0.0.1:8089/calc.wsdl
//gsoapns service location: http://127.0.0.1:8089/cal
//gsoapns schema  namespace:    urn:calc
int ns__add(double a, double b, double *result);
int ns__sub(double a, double b, double *result);
int ns__mul(double a, double b, double *result);
int ns__div(double a, double b, double *result);
int ns__pow(double a, double b, double *result);

二多线程服务器关键代码

#include  
#include  "calc.nsmap"
#include  "soapH.h"

/
///宏与全局变量的定义
#define  BACKLOG (100)  
#define  MAX_THR (10)   
#define  MAX_QUEUE (1000)


pthread_mutex_tqueue_cs;                       //队列锁
pthread_cond_t queue_cv;                         //条件变量
SOAP_SOCKET     queue[MAX_QUEUE];   //数组队列
int                          head =0, tail =0;         //队列头队列尾初始化         
//


//
void *      process_queue(void*);        //线程入口函数
int         enqueue(SOAP_SOCKET); //入队列函数
SOAP_SOCKET dequeue(void);         //出队列函数

//
//线程入口函数
void * process_queue(void * soap)
{
  struct soap * tsoap = (struct soap *)soap;
  for(;;)
  {
        tsoap->socket = dequeue();
        if(!soap_valid_socket(tsoap->socket))
       {
         break;
        }
        soap_serve(tsoap);
        soap_destroy(tsoap);
        soap_end(tsoap);
  }
  return NULL;
}

//入队列操作
int enqueue(SOAP_SOCKET sock)
{
  int status = SOAP_OK;
  int next;
  pthread_mutex_lock(&queue_cs);
  next = tail +1;
  if (next >= MAX_QUEUE) 
    next = 0;
  if (next == head) 
      status = SOAP_EOM;
  else
  {
    queue[tail] =sock;
    tail = next;
  }
  pthread_cond_signal(&queue_cv);
  pthread_mutex_unlock(&queue_cs);
  return status;
}

//出队列操作
SOAP_SOCKET dequeue()
{
  SOAP_SOCKET sock;
  pthread_mutex_lock(&queue_cs);
   while (head == tail )
   {
          pthread_cond_wait(&queue_cv,&queue_cs);
   }
  sock = queue[head++];
  if (head >= MAX_QUEUE)
        {
    head =0;
  }
  pthread_mutex_unlock(&queue_cs);
  return sock;
}


//具体服务方法
//加法的实现
int ns__add(struct soap *soap, double a, double b, double *result)
{
      *result = a + b;
      return SOAP_OK;

//减法的实现
int ns__sub(struct soap *soap, double a, double b, double *result)

     *result = a - b;
     return SOAP_OK;

//乘法的实现
int ns__mul(struct soap *soap, double a, double b, double *result)

     *result = a * b;
     return SOAP_OK;

//除法的实现
int ns__div(struct soap *soap, double a, double b, double *result)

   if (b)
       *result = a / b;
   else
  {
         char *s = (char*)soap_malloc(soap,1024);
         sprintf(s,"Can't">http://tempuri.org/">Can't divide %f by %f", a, b);
         return soap_sender_fault(soap,"Division by zero", s);
  }
  return SOAP_OK;

//乘方的实现
int ns__pow(struct soap *soap, double a, double b, double *result)

  *result = pow(a, b);
  if (soap_errno == EDOM) /* soap_errno 和errorno类似,但是和widnows兼容 */
  { 
    char *s = (char*)soap_malloc(soap, 1024);
    sprintf(s, "Can't take the power of %f to %f", a, b);
    sprintf(s,"Can't">http://tempuri.org/">Can't take power of %f to %f", a, b);
    return soap_sender_fault(soap, "Power function domainerror", s);
  }
  return SOAP_OK;
}

//
//主函数
int main(int argc,char ** argv)
{
  struct soap ServerSoap;
     //初始话运行时环境
    soap_init(&ServerSoap);
    //如果没有参数,当作CGI程序处理
    if (argc <2) 
    {       
           //CGI 风格服务请求,单线程
         soap_serve(&ServerSoap);
          //清除序列化的类的实例
         soap_destroy(&ServerSoap);
         //清除序列化的数据
       soap_end(&ServerSoap);     
   }else
   {
     struct soap * soap_thr[MAX_THR];
     pthread_t tid[MAX_THR];
     int i,port = atoi(argv[1]);
     SOAP_SOCKET m,s;
      //锁和条件变量初始化
     pthread_mutex_init(&queue_cs,NULL);
     pthread_cond_init(&queue_cv,NULL);
     //绑定服务端口
    m = soap_bind(&ServerSoap,NULL,port,BACKLOG);
    //循环直至服务套接字合法
    while (!soap_valid_socket(m))
   {
               fprintf(stderr,"Bind port error! ");
               m = soap_bind(&ServerSoap,NULL,port,BACKLOG);
    }
    fprintf(stderr,"socket connection successful %d",m);
                
     //生成服务线程
    for(i = 0; i <MAX_THR; i++)

{
      soap_thr[i] = soap_copy(&ServerSoap);
      fprintf(stderr,"Starting thread %d",i);
      pthread_create(&tid[i],NULL,(void*(*)(void*))process_queue,(void*)soap_thr[i]);
    }
                
    for(;;)
    {
      //接受客户端的连接
      s = soap_accept(&ServerSoap);
      if (!soap_valid_socket(s)) 
      {
        if (ServerSoap.errnum) 
                               {
         soap_print_fault(&ServerSoap,stderr);
          continue;
        }else
        {
         fprintf(stderr,"Server timed out ");
          break;
        }
      }
       //客户端的IP地址
      fprintf(stderr,"Accepted connection fromIP= %d.%d.%d.%d socket = %d ",
                              ((ServerSoap.ip)>>24)&&0xFF,((ServerSoap.ip)>>16)&0xFF,((ServerSoap.ip)>>8)&0xFF,(ServerSoap.ip)&0xFF,(ServerSoap.socket));
      //请求的套接字进入队列,如果队列已满则循环等待
       while(enqueue(s) == SOAP_EOM)
               Sleep(1000);
    }
    //服务结束后的清理工作
    for(i = 0; i < MAX_THR; i++)
    {
      while (enqueue(SOAP_INVALID_SOCKET) ==SOAP_EOM) 
       {
           Sleep(1000);
      }
    }
    for(i=0; i< MAX_THR; i++)
    {
      fprintf(stderr,"Waiting for thread %d toterminate ..",i);
      pthread_join(tid[i],NULL);
      fprintf(stderr,"terminated ");
      soap_done(soap_thr[i]);
      free(soap_thr[i]);
    }
    pthread_mutex_destroy(&queue_cs);
    pthread_cond_destroy(&queue_cv);
  }
    //分离运行时的环境
  soap_done(&ServerSoap);
  return 0;
}

在windows下配置pthread

Pthread是由POSIX提出的一套通用的线程库,在linux平台下,它被广泛的支持,而windows平台下,却并不被支持,而pthreads-w32为我们提供了解决方案,本文我们准备在我们的windows平台下进行pthread-w32的安装,在网络上有类似的文章,但是讲的都是比较老的平台,在windows8下支持并不全面,不过可以作为参考。我们在这里贴出几个网址,供参考使用。

Windows 7 64bit和Visual Studio 2010下安装及使用Pthread-w32 2.8

windows下使用pthread库(转)

如果你的是XP系统或者win7 32位系统,那么,那两篇文章已经足以你完成pthread-w32的安装了。现在,我们开始讲我们的尝试过程。

一、安装平台

windows8 64位系统,MicrosoftVisual Studio 2012

二、pthreads-w32下载地址

我们这里下载最新版本pthreads-w32-2-9-1

ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-2-9-1-release.zip

下载后解压,可以看到共有三个文件夹

我们用到的主要是“Pre-built.2”这个文件夹下的三个文件夹,分别是动态链接库、头文件、静态链接库

三、配置头文件及静态链接库

这里有多种方式,我们这里只提到我们用到的一种,总之目的是让我们建立的工程能够找到对应的头文件、静态库文件,以及运行时程序能够找到动态链接库文件。

这里,我们直接把头文件拷贝到Visual Studio的默认路径的头文件中,即把include文件夹中的三个文件直接拷贝到VisualStudio安装目录下VC->include文件夹下,例如我将include中文件拷贝到的位置是

E:\ProgramFiles\Microsoft Visual Studio 11.0\VC\include

这样,我们就不必每次在项目用到时都配置一遍,特别是在Visual Studio2012貌似不支持全局的头文件配置时(不确定,如果谁找到了可以告诉我一声),这种方式对于经常会建一些小项目的人来说,相对节省时间。

同样的办法与原因,我们也可以把lib文件夹下的内容拷贝到Visual Studio安装目录下默认的lib寻找路径中,即VC->lib中,例如我将lib文件夹下的x64与x86两个文件直接拷贝到

E:\Program Files\Microsoft Visual Studio 11.0\VC\lib

的下面。

四、配置动态链接库

和头文件和静态链接库的配置方式相似,我们这里将dll文件夹的内容放到我们程序能够找到的位置,我们的方案是

把dll下的x64文件夹下的两个文件,即pthreadGC2.dll与pthreadVC2.dll拷贝到C:\Windows\System32下(用于64位程序的运行)

把dll下的x86文件夹下的五个文件,拷贝到C:\Windows\SysWOW64下(用于32位程序的运行),注意一下,千万不能将这些文件拷贝反位置,否则,程序运行时会提示说找不到对应的dll文件。这些在网上的很多文章中都被忽略掉了,所以我们特别提出。

五、运行测试

完成以上配置之后,我们运行一下测试程序,证明我们的配置完成了

//main.cpp

#include <stdio.h>

#include <pthread.h>

#include <assert.h>

#pragmacomment(lib,"x86/pthreadVC2.lib")

void* Function_t(void* Param)

{

printf("我是线程! ");

pthread_tmyid = pthread_self();

printf("线程ID=%d ", myid);

returnNULL;

}

int main()

{

pthread_tpid;

pthread_attr_tattr;

pthread_attr_init(&attr);

pthread_attr_setscope(&attr,PTHREAD_SCOPE_PROCESS);

pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

pthread_create(&pid,&attr, Function_t, NULL);

printf("========================================");

getchar();

pthread_attr_destroy(&attr);

return0;

}

这里,我们需要注意的是我们的第6行代码,我们需要在代码中包含入静态链接库(注意,根据不同的编译选项,选择x86还是x64,如果不相配,将无法链接完成)

#pragmacomment(lib,"x86/pthreadVC2.lib")

gsoap实例代码下载:http://download.csdn.net/detail/byxdaz/9549883

参考资料:

官网源代码: https://sourceforge.net/projects/gsoap2/

帮助文档:http://www.cs.fsu.edu/~engelen/soapdoc2.html

gsoap使用总结:http://www.cnblogs.com/linxr/archive/2011/10/17/2215285.html

C#访问gsoap的服务:http://blog.csdn.net/caowei880123/article/details/49129211#

windows下使用pthread库:http://blog.csdn.net/g_spider/article/details/6023698#comments

转自:https://blog.csdn.net/byxdaz/article/details/51679117

相关文章:

SQL时间相关 - SQL日期,时间比较

SQL Server 中时间比较 例子: select count(*) from table where DATEDIFF ([second], 2004-09-18 00:00:18, 2004-09-18 00:00:19) > 0 说明 select DATEDIFF(day, time1 , time2) 对应示例语句如下 select DATEDIFF(day, 2010-07-23 0:41:18, 2010-07-23 23:41:18) …

SQL Server 2008 的CDC功能

CDC(Change Data Capture)通过对事务日志的异步读取&#xff0c;记录DML操作的发生时间、类型和实际影响的数据变化&#xff0c;然后将这些数据记录到启用CDC时自动创建的表中。通过cdc相关的存储过程&#xff0c;可以获取详细的数据变化情况。由于数据变化是异步读取的&#x…

1010 Radix

目录 总结 解题过程 总结 1. 短小精悍的一道二分算法题&#xff0c;总体思路是&#xff0c;将字符串1(如果tag不是1将两个字符串调换一下即可)转化为10进制&#xff0c;再用二分法看能否找到另一个进制使得两个字符串的10进制数相等。 2. 本题的三个函数关系是binarySearch…

喜闻乐见的const int *p、int* const p、const int* const p

不废话直接代码示例&#xff1a; 1 void f(const int *p) {2 3 int b 10;4 5 *p 10; // error6 7 p &b; // fine8 9 } 10 11 void f(int* const p) { 12 13 int b 10; 14 15 *p 10; // fine 16 17 p &b; // error 18 19 } 20 21 v…

Microsoft Visual Studio 2012 添加实体数据模型

Microsoft Visual Studio 2012 添加实体数据模型 1、创建一个web项目 2、添加ADO实体数据模型&#xff0c;如下图&#xff1a; 3、选择 从数据库生成&#xff0c;然后下一步 4、新建连接&#xff0c;如下图&#xff1a; 5、填写服务器名等&#xff0c;如下图&#xff1a; 6、选…

5.1软件升级的小阳春

现在正在去白山的车上&#xff0c;刚睡醒。习惯性的拿出手机上网&#xff0c;UCWEB提醒有最新版本升级&#xff0c;使用尚邮接收邮件的时候同样提醒有信版本升级。 公司产品9.0也正式完成&#xff0c;昨天整个小组的同事开始在领地咖啡馆&#xff0c;进行新需求的确认。 4月末5…

1030 完美数列(二分解法)

1. 将整型序列从小到大排序后&#xff0c;这道题的本质是&#xff0c;对于每一个元素i&#xff0c;找出最后一个满足p*A[i]>A[j]的元素j&#xff0c;可以转化为找出第一个不满足p*A[i]>A[j]也即p*A[i]<A[j]的元素j。再用j-1。 2.LL product (LL)p*A[i];这里后面两个…

javascript变量声明 及作用域

javascript变量声明提升(hoisting) http://openwares.net/js/javascript_declaration_hoisting.html 可能要FQ一下 javascript的变量声明具有hoisting机制&#xff0c;JavaScript引擎在执行的时候&#xff0c;会把所有变量的声明都提升到当前作用域的最前面。 先看一段代码 123…

【转载】全面理解javascript的caller,callee,call,apply概念(修改版)

今天写PPlayer&#xff0c;发现有段代码引起了我的兴趣&#xff1a; var Class { create: function() { return function() { this.initialize.apply(this, arguments); } } } 这是高手写的&#xff0c;实现了创建一个类&#xff08;其实就是对象&#xff0c;函数对象&#xf…

springMVC自定义全局异常

SpringMVC通过HandlerExceptionResolver处理程序异常&#xff0c;包括Handler映射&#xff0c;数据绑定以及目标方法执行时所发生的异常。 SpringMVC中默认是没有加装载HandlerExceptionResolver&#xff0c;我们需要在SpringMVC.xml中配置 <mvc:annotation-driven /> 1、…

1030 完美数列(two pointers解法)

1. 这道题出现在二分法&#xff0c;但是特殊之处在于&#xff0c;双指针是嵌套的&#xff0c;程序看上去有些像暴力枚举&#xff0c;但其实是利用了&#xff0c;如果i<j&#xff0c;a[i]*p>a[j]&#xff0c;那么一定有k在[i,j]范围内&#xff0c;a[i]*p>a[k]&#xff…

alsa声卡切换

环境 ubuntu12.04 因为桌面版的默认装了&#xff0c;而且调声音也很方便&#xff0c;这里说一下server版下的配置&#xff0c;毕竟做开发经常还是用server版的 1.安装 apt-get install alsa-base 它会把alsa-utils也一块装了&#xff0c;这是个工具包&#xff0c;如果没装的话 …

asp.net获取网站路径

网站在服务器磁盘上的物理路径: HttpRuntime.AppDomainAppPath 虚拟程序路径: HttpRuntime.AppDomainAppVirtualPath 任何于Request/HttpContext.Current等相关的方法, 都只能在有请求上下文或者页面时使用. 即在无请求上下文时,HttpContext.Current为null. 而上面提到的方法一…

iOS 绘制圆角

级别&#xff1a; ★☆☆☆☆ 标签&#xff1a;「iOS切圆角」「layer圆角」「CAShapeLayer圆角」 作者&#xff1a; XsH 审校&#xff1a; QiShare团队 项目中会常有圆角&#xff08;或圆形&#xff09;显示视图的需求&#xff08;比如用户头像的显示&#xff09;&#xff0c;也…

(C++)归并排序的递归与非递归实现

递归实现 merge函数利用的是双指针技巧降低复杂度。 mergeSort函数使用了递归&#xff0c;当中先对左右序列各调用一次mergeSort&#xff0c;再对整个序列调用merge。就按照最浅层的归并的思想去理解&#xff0c;不要大脑走到哪就step in。 另外mergeSort进入递归有个left&l…

SnackbarUtilDemo【Snackbar的封装类】

版权声明&#xff1a;本文为HaiyuKing原创文章&#xff0c;转载请注明出处&#xff01; 前言 这个工具类参考的是《没时间解释了&#xff0c;快使用Snackbar!——Android Snackbar花式使用指南》&#xff0c;代码几乎一样&#xff0c;所以想要了解具体原理或者更详细信息请阅读…

java通过代理访问网络

使用代理方式连接到网络 Testpublic void t13(){String charset "utf-8" ; String proxyHost "代理地址" ; int proxyPort 1234 ; //代理端口String proxyUrsername "登陆代理服务器的用户名" ; String proxyPassword "登陆代理服务器…

poj2503 Babelfish

跟poj3349很类似的题目&#xff0c;这题还稍简单。用qsort快速排序和二分查找可以很轻松AC。以下是代码&#xff1a; Run IDUserProblemResultMemoryTimeLanguageCode LengthSubmit Time5135234zen_chou2503Accepted2356K547MSC1212B2009-05-11 20:12:26Code1 #include <std…

(C语言)一种简易记法:生成[a,b]范围内的随机整数

1. 添加头文件 #include<stdlib.h> #include<time.h> 2. 初始化随机种子 srand((unsigned)time(NULL)); 3. 确定元素个数b-a1&#xff0c;以及最小元素 printf("%d",rand()%(b-a1)a);//生成[a,b]之间的数 printf("%d",rand()%1001);//生成…

IE和火狐都支持的方法(输入用户名和密码后按下 enter 键)

在Firefox中老报"event is not defined”错误&#xff01;原因是因为在Firefox中使用了不同的事件对象模型,不同于IE Dom&#xff0c;用的是W3C Dom。 document.οnkeydοwnfunction mykeyDown(e){ //compatible IE and firefox because there is not event in fir…

数据库中存储与读取文件

if exists (select * from dbo.sysobjects where id object_id(N[dbo].[p_binaryIO]) and OBJECTPROPERTY(id, NIsProcedure) 1)drop procedure [dbo].[p_binaryIO]GO /*--bcp 实现二进制文件的导入导出 支持image,text,ntext字段的导入/导出 image适合于二进制文件,包括:Wor…

洛谷P3723 [AH2017/HNOI2017]礼物(FFT)

传送门 首先&#xff0c;两个数同时增加自然数值相当于只有其中一个数增加&#xff08;此增加量可以小于0&#xff09; 我们令$x$为当前的增加量&#xff0c;${a},{b}$分别为旋转后的两个数列&#xff0c;那么$$ans\sum_{i1}^n(a_ix-b_i)^2$$ 然后把第$i$项提出来并展开&#x…

1035 插入与归并

1. 这一题&#xff0c;首先要会插入排序和归并排序的写法。对于归并排序&#xff0c;可以用非递归sort最简便。把每一趟的结果存进二维数组。 2. 单独封装一个函数&#xff0c;比较两个一维数组是否完全一样。 3. 由于归并比插入的复杂度低&#xff0c;趟数少&#xff0c;所以…

代码设置LinearLayout的高度

问题描述我想把这个LinearLayout宽度设置成为FILL_PARENT&#xff0c;源码如下LinearLayout checkboxLinearLayout (LinearLayout) getLayoutInflater().inflate(R.layout.checkboxdoitem, null);LayoutParams params (LayoutParams) checkboxLinearLayout.getLayoutParams();…

精通Spring Boot —— 第十五篇:使用@ControllerAdvice处理异常

在Spring 3.2中&#xff0c;新增了ControllerAdvice、RestControllerAdvice 注解&#xff0c;可以用于定义ExceptionHandler、InitBinder、ModelAttribute&#xff0c;并应用到所有RequestMapping、PostMapping&#xff0c; GetMapping注解中。接下来我将通过代码展示如何使用这…

架构设计之分布式文件系统

1&#xff1a;类图 2&#xff1a;数据结构 create table TBCOFILE ( FILEID INTEGER not null, FILETIME DATE, TYPE VARCHAR2(10), USERID INTEGER, IP VARCHAR2(20), APPTYPE INTEGER default 0) 3&#xff1a;开发步骤 1&#xff1a;从数据库申…

1029 Median

1. 开始测试点3和6答案错误&#xff0c;原因是没有考虑到&#xff0c;给的两个数列有可能长度相差很大&#xff0c;某个数列还没到中位数&#xff0c;就结束了。 2. 这题的底子是用two pointers按照非递减的顺序合并两个数列&#xff0c;无非是再确定一下中间那个数的下标&…

理解系统底层的概念是多么重要

理解系统底层的概念是多么重要 ——趋势科技邹飞评《程序员的自我修养》 关于《程序员的自我修养》这本书&#xff0c;最初是在和博文的周筠老师MSN上谈起&#xff0c;当时听周老师提及这本书是一本关于链接和装载等系统软件知识的书籍&#xff0c;当时就很感兴趣&#xff0c;因…

session删除

删除一个session值&#xff1a; session_unset(变量); session_destroy(变量); 删除一个cookie&#xff1a; 注意第二个参数中手册中的说明是&#xff1a; Cookie 必须用和设定时的同样的参数才能删除。如果其值一个空字符串&#xff0c;或者是 FALSE&#xff0c;并且其它的参数…

Android学习路线

Android学习路线 第一阶段&#xff1a;Java面向对象编程 1.Java基本数据类型与表达式&#xff0c;分支循环。 2.String和StringBuffer的使用、正则表达式。 3.面向对象的抽象&#xff0c;封装&#xff0c;继承&#xff0c;多态&#xff0c;类与对象&#xff0c;对象初始化和回…