服务端使用gsoap库(版本为2.8.9),参考官方示例的httpdatest.c编写,服务的内容很简单,传入两个整数,返回它们的和。
1.先编译安装gsoap 2.8.9,你也可以安装最新的版本,可以得到soapcpp2
2.创建wsaddgsoapserverdefine.h,定义一个web service method
int ns__wsadd(int a, int b, int *result);
3.使用soapcpp2生成需要的其他文件
soapcpp2 -c wsaddgsoapserverdefine.h
4.修改生成的ns.wsdl,将
<SOAP:address location="http://localhost:80"/>
改为实际服务器的IP(域名)和服务端口,比如
<SOAP:address location="http://192.168.1.132:8000"/>
5.创建wsaddgsoapserver.c,编写服务核心代码
#include "httpda.h"
#include "soapH.h"
#include "ns.nsmap"
int run_serve(int port);
int main(int argc, char *argv[])
{
return run_serve(8000);
}
int run_serve(int port)
{
struct soap *soap = soap_new1(SOAP_XML_INDENT);
int ret;
soap_register_plugin(soap, http_da);
if (!soap_valid_socket(soap_bind(soap, NULL, port, 100)))
soap_print_fault(soap, stderr);
else
{
fprintf(stderr, "Bind to port %d successful\n", port);
soap->accept_timeout = 3600; /* let server time out after one hour */
for (;;)
{
int sock = soap_accept(soap);
if (!soap_valid_socket(sock))
{
if (soap->errnum)
soap_print_fault(soap, stderr);
else
{
fprintf(stderr, "Server timed out\n");
break;
}
}
fprintf(stderr, "Accepting socket %d connection from IP %d.%d.%d.%d\n", sock, (int)(soap->ip>>24)&0xFF, (int)(soap->ip>>16)&0xFF, (int)(soap->ip>>8)&0xFF, (int)soap->ip&0xFF);
if (soap_serve(soap))
soap_print_fault(soap, stderr);
fprintf(stderr, "Served\n\n");
soap_destroy(soap);
soap_end(soap);
}
}
ret = soap->error;
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
return ret;
}
int ns__wsadd(struct soap *soap, int a, int b, int *result)
{
if (soap->userid && soap->passwd) /* Basic authentication: the password was sent in the clear */
{
if (!strcmp(soap->userid, "username") && !strcmp(soap->passwd, "password"))
{
*result=a+b;
return SOAP_OK;
}
}
return 401; /* Not authorized */
}
6.编辑stdsoap2.c,修改http_get函数的实现,目的是接下来Visual Studio中添加服务引用时能够发现该服务。修改如下:
//static int
//http_get(struct soap *soap)
//{ (void)soap;
// DBGLOG(TEST, SOAP_MESSAGE(fdebug, "HTTP GET request\n"));
// return SOAP_GET_METHOD;
//}
static 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("ns.wsdl", "rb"); // open WSDL file to copy
if (!fd)
{
return 404; // return HTTP not found error
}
soap->http_content = "text/xml"; // HTTP header with text/xml content
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; // can't send, but little we can do about that
}
}
fclose(fd);
soap_end_send(soap);
return SOAP_OK;
}
7.编译生成服务端
gcc -DWITH_OPENSSL -o wsaddgsoapserver wsaddgsoapserver.c soapC.c soapServer.c httpda.c md5evp.c threads.c stdsoap2.c -lssl -lcrypto -lz
8../wsaddgsoapserver运行服务端,可以在浏览器中输入http://192.168.1.132:8000/?wsdl,查看服务端的http get服务部分是否正常工作
9.编写Windows Phone客户端,新建一个Windows Phone工程(如果没有的话),右键解决方案中的引用,添加服务引用,在地址栏输入http://192.168.1.132:8000/?wsdl,点击前往,VS将自动连接服务端解析出服务端提供的服务以及方法,如下:
10.自定义命名空间,比如WSAddServiceReference,点击确定就可以使用了。
11.客户端核心代码如下:
private string EncodeBasicAuthenticationCredentials(string username, string password)
{
//first concatenate the user name and password, separated with :
string credentials = username + ":" + password;
//Http uses ascii character encoding, WP7 doesn’t include
// support for ascii encoding but it is easy enough to convert
// since the first 128 characters of unicode are equivalent to ascii.
// Any characters over 128 can’t be expressed in ascii so are replaced
// by ?
var asciiCredentials = (from c in credentials
select c <= 0x7f ? (byte)c : (byte)'?').ToArray();
//finally Base64 encode the result
return Convert.ToBase64String(asciiCredentials);
}
private void button_CallWSAdd_Click(object sender, RoutedEventArgs e)
{
WSAddServiceReference.ServicePortTypeClient SPTC = new WSAddServiceReference.ServicePortTypeClient();
SPTC.wsaddCompleted += (s, arg) =>
{
if (arg.Error != null)
{
textBox_WSAddResult.Text = string.Format("Error:{0}", arg.Error.Message);
return;
}
textBox_WSAddResult.Text = arg.Result.ToString();
};
var credentials = EncodeBasicAuthenticationCredentials("username", "password");
using (OperationContextScope scope = new OperationContextScope(SPTC.InnerChannel))
{
HttpRequestMessageProperty request = new HttpRequestMessageProperty();
request.Headers[System.Net.HttpRequestHeader.Authorization] = "Basic " + credentials;
OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, request);
SPTC.wsaddAsync(int.Parse(textBox_WSAddArgA.Text), int.Parse(textBox_WSAddArgB.Text));
}
}
12.编译运行客户端,和服务端交互的界面如下:
13.抓包结果如下:
POST / HTTP/1.1
Accept: */*
Referer: file:///Applications/Install/89591F69-A04D-4BEF-B181-4FA364ECD820/Install/
Content-Length: 179
Accept-Encoding: identity
Content-Type: text/xml; charset=utf-8
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
SOAPAction: ""
User-Agent: NativeHost
Host: 192.168.1.132:8000
Connection: Keep-Alive
Cache-Control: no-cache
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><wsadd xmlns="http://tempuri.org/ns.xsd"><a xmlns="">12</a><b xmlns="">34</b></wsadd></s:Body></s:Envelope>
HTTP/1.1 200 OK
Server: gSOAP/2.8
Content-Type: text/xml; charset=utf-8
Content-Length: 436
Connection: close
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://tempuri.org/ns.xsd">
<SOAP-ENV:Body>
<ns:wsaddResponse>
<result>46</result>
</ns:wsaddResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
14.服务端完整代码可以在这里下载: http://download.youkuaiyun.com/detail/chenxupro/6400275
15.客户端完整代码也可以在我的资源里面下载,链接暂时还看不到。