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 );
使用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的反序列化數據(這時你需要自己釋放)。
為提升服務性能,減少數據傳輸量,建議所有輸出都采用字符方式的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)大小的內存.
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
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
}
通過更改在stdsoap2.h文件中 SOAP_BUFLEN 宏,增加緩存大小,默認緩存大小為65536
代碼請參看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字符編碼*/
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;
}
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