因为工作中需要用到远程方法调用(RPC?)。本人标准的懒人一枚。so向谷哥询问有没有现成的比较好用的东西可用。于是就发现了gsoap。目前最新版本是2.8.8,这个东西的神奇之处在于可以轻松的传送结构体,让你可以专心做数据处理,而且集成web service方便接口发布。而且再在前面放一web server做个反向代理,就算是分布式计算啦!
一看开发包我勒个去,toolkit 13.8M的大家伙啊,看了看发现其实有用的东西不多。因为里面有linux,mac,win三个平台的二进制工具,大片代码文件是编译其他平台gsoap工具用的,一般情况也用不到。做linux的C语言远程调用需要的只有这么几个:stdsoap2.c、stdsoap2.h、typemap.dat和bin/linux386下的soapcpp2、wsdl2h,取出这5个文件那个大压缩包就可以扔了。(-_-!这是为熟么捏?)
初期开发用c语言的.h头文件定义接口,后面生成的wsdl文件(Web Services Description Language)是基于xml格式的接口说明文件。可以挂在web上,供调用者做各种语言开发。
写个小demo,gettime.h:接口定义
1
2
3
4
5
6
7
8
|
//gettime.h http://btdn.org
typedef
struct
_date
{
int
timezone;
long
dv;
}date;
int
h__gettime(date* data);
|
然后执行命令
(调用者要先取得wsdl文件后执行./wsdl2h -c h.wsdl取得C的.h文件,-c生成纯c代码,下同)
./soapcpp2 -c gettime.h
gettime_Server.c:服务端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
//gettime_Server.c http://btdn.org
#include "soapH.h"
#include "h.nsmap"
#include <pthread.h>
#define TIME_ZONE 8
#define CST_TIME(a) (time(NULL)+a*60*60)
#define PORT 10001
#define BACKLOG 10
void
* process_request(
void
* data);
//处理线程
int
http_post(
struct
soap *soap,
const
char
*endpoint,
const
char
*host,
int
port,
const
char
*path,
const
char
*action,
size_t
count);
//post响应回调函数
int
http_get(
struct
soap *soap);
//get响应回调函数
int
main()
{
int
m;
pthread_t tid;
struct
soap soap,*tsoap;
soap_init(&soap);
//设定post、get回调函数,实现类似web service功能,展示wsdl发布调用接口
soap.fget = http_get;
soap.fpost = http_post;
soap.accept_timeout = 5;
//soap.里有各种timeout
m = soap_bind(&soap, NULL, PORT, BACKLOG);
//bind、accept同socket
if
(m < 0)
{
soap_print_fault(&soap, stderr);
exit
(-1);
}
while
(1)
{
m = soap_accept(&soap);
if
(!soap_valid_socket(m))
{
if
(soap.errnum)
{
soap_print_fault(&soap, stderr);
continue
;
}
fprintf
(stderr,
"server timed out\n"
);
continue
;
}
fprintf
(stderr,
"accepts socket %d connection from IP %ld.%ld.%ld.%ld\n"
, m, (soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF);
tsoap = soap_copy(&soap);
if
(!tsoap)
{
fprintf
(stderr,
"Error in soap_copy.\n"
);
continue
;
}
//创建线程处理可以使复杂方法有更好的响应能力
if
(0 != pthread_create(&tid,NULL,process_request,tsoap))
{
fprintf
(stderr,
"Error in pthread_create.\n"
);
free
(tsoap);
continue
;
}
}
return
0;
}
//接口函数。这里准备返回的数据
int
h__gettime(
struct
soap *soap, date* data)
{
data->dv = CST_TIME(TIME_ZONE);
data->timezone = TIME_ZONE;
return
SOAP_OK;
}
//request响应线程方法
void
* process_request(
void
* data)
{
soap_serve((
struct
soap*)data);
// 会自动调用具体的接口函数
soap_destroy((
struct
soap*)data);
// dealloc C++ data
soap_end((
struct
soap*)data);
// dealloc data and clean up
soap_done((
struct
soap*)data);
// detach soap struct
free
(data);
return
NULL;
}
//这里简单把wsdl文件内容给浏览器,web service不是重点,意思一下。
int
http_get(
struct
soap *soap)
{
FILE
*fd = NULL;
fd =
fopen
(
"h.wsdl"
,
"rb"
);
//h.wsdl就是前面提到的发布用的接口说明文件
if
(!fd)
return
404;
//404你懂的
soap->http_content =
"text/xml"
;
//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;
}
//同上
int
http_post(
struct
soap *soap,
const
char
*endpoint,
const
char
*host,
int
port,
const
char
*path,
const
char
*action,
size_t
count)
{
return
http_get(soap);
}
|
gettime_Client.c:客户端代码,这里就简单多了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
//gettime_Client.c http://btdn.org
#include "soapH.h"
#include "h.nsmap"
#define SERVER_ADDR "http://localhost:10001"
#define ACTION ""
int
main()
{
date data;
struct
soap soap;
struct
tm
*
tm
;
char
tm_buf[64];
soap_init(&soap);
//soap_set_namespaces(&soap, namespaces);
memset
(&data,0,
sizeof
(date));
//调用远程方法
if
(SOAP_OK == soap_call_h__gettime(&soap, SERVER_ADDR, ACTION, &data))
{
tm
=
gmtime
(&data.dv);
strftime
(tm_buf,
sizeof
(tm_buf),
"%Y-%m-%d %H:%M:%S"
,
tm
);
printf
(
"timezone:%d\n"
"time:%s\n"
,data.timezone
,tm_buf);
}
else
{
fprintf
(stderr,
"Error in soap_call_h__gettime.\n"
);
}
soap_destroy(&soap);
soap_end(&soap);
soap_done(&soap);
return
0;
}
|
Makefile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
CC = gcc
CFLAGS = -Os -Wall
LDFLAGS = -lpthread
COMMON_OBJS = soapC.o stdsoap2.o
SERVER_OBJS = gettime_Server.o soapServer.o
CLIENT_OBJS = gettime_Client.o soapClient.o
OBJS = $(COMMON_OBJS) $(SERVER_OBJS) $(CLIENT_OBJS)
TARGET_SERVER = gts
TARGET_CLIENT = gtc
all:$(TARGET_SERVER) $(TARGET_CLIENT)
echo
"All Done"
$(TARGET_SERVER):$(SERVER_OBJS) $(COMMON_OBJS)
$(CC) $(LDFLAGS) $(SERVER_OBJS) $(COMMON_OBJS) -o $(TARGET_SERVER)
$(TARGET_CLIENT):$(CLIENT_OBJS) $(COMMON_OBJS)
$(CC) $(LDFLAGS) $(CLIENT_OBJS) $(COMMON_OBJS) -o $(TARGET_CLIENT)
$(OBJS):%.o:%.c
$(CC) -c $(CFLAGS) $< -o $@
clean:
rm
-f $(TARGET_SERVER) $(TARGET_CLIENT) $(OBJS)
|
make一下就可以执行了,大功告成^-^!
[cz@myhost soap_demo]$ ./gts
accepts socket 4 connection from IP 10.0.2.2[cz@myhost soap_demo]$ ./gtc
timezone:8
time:2012-03-05 16:25:59