简介
原先是直接使用的Socket来进行网络编程,但遇到高并发我就难以招架了,与是在网上找了一下,发现了开源的gSoap跨平台库,于是就开始尝试使用起来。
官方主页:https://www.genivia.com/products.html
说明文档:https://www.genivia.com/doc/soapdoc2.html
源码下载:https://sourceforge.net/projects/gsoap2/
由于现在所要做的程序只需要短连接,所以就只用到了gSoap所支持的RESTful功能。
本文只讲述在Windows环境下的编程,linux下经测试流程是一样的。
开发步骤
创建Webservice相关声明头文件
该文件需要按特定格式书写,并且注释有特定的意义,详细可看文档。我说创建的最简化声明文件“Webservice.h”文件如下,名字可随意,不影响项目。
//gsoap ns service name: GameWebservice
//gsoap ns service location: http://localhost
//gsoap ns service namespace: urn:GameWebservice
int ns__test(void*);
“ns_test”函数是SOAP远程调用函数,因为使用的是RESTful,所以不用关心,但必须声明一个。
使用“soapcpp2”创建项目源文件
“soapcpp2.exe”在源码目录下“gsoap/bin/win32”目录中,linux下的则需要自己重新编译,文档中也有说明。
使用如下命令创建。
soapcpp2.exe -0 -S -L -r -w -x GameWebService.h
结果如下图:
一共生成了6个文件,有5个是必要的,还有一个是生成的说明文件,可以不要。
- soapStub.h
- soapServer.cpp
- soapH.h
- soapC.cpp
- GameWebservice.nsmap
创建c++工程,并添加相关文件
为了简单,我使用vs创建一个c++控制台工程。然后将上面所说的5个文件添加到工程中。
添加gSoap源文件,在“gsoap”目录下。
- stdsoap2.h
- stdsoap2.cpp
为了方便使用RESTful,将“gsoap\plugin”中的如下文件添加到工程中。
- httppost.h 与 httppost.c
- httpget.h 与 httpget.c
由于需要使用到socket,所以要在vs的附加依赖项中添加“ws2_32.lib;”。
编写main
# include <iostream>
using namespace std;
//gsoap
# include "soapH.h"
# include "httpget.h"
# include "httppost.h"
# include "GameWebservice.nsmap"//重要!!该文件不要重复包含,会产生重复定义
int HttpGetHandler(struct soap* soap);
int HttpPostHandler(struct soap* soap);
int CheckAuthorization(soap * soap);
//Post根据mime分配回调
struct http_post_handlers ghttpPostHndlers[] =
{
{ "POST", HttpPostHandler },
{ 0 }
};
//用于简单认证的账户和密码
#define USERID "admin"
#define PASSWORD "123456"
//设置
#define LISTENPORT 8080
#define LISTENMAX 100
int main()
{
struct soap soap;
soap_init(&soap);//初始化
//注册get请求回调函数
soap_register_plugin_arg(&soap, http_get, (void*)HttpGetHandler);
//注册post请求回调函数
soap_register_plugin_arg(&soap, http_post, (void*)ghttpPostHndlers);
//用于简单认证,设置帐号密码,选加
soap.userid = USERID;
soap.passwd = PASSWORD;
//
SOAP_SOCKET ssock = soap_bind(&soap, 0, LISTENPORT, LISTENMAX);
fprintf(stderr, "Start accept client !\n");
while (true)
{
//监听客户端连接
SOAP_SOCKET ssockclient = soap_accept(&soap);
fprintf(stderr, "Client Connect !\n");
//处理连接
soap_serve(&soap);//运行soap
}
//销毁服务端
soap_destroy(&soap);
soap_end(&soap);
soap_done(&soap);
return 0;
}
//简单认证
int CheckAuthorization(soap * soap)
{
if (!soap->userid || !soap->passwd ||
strcmp(soap->userid, USERID) ||
strcmp(soap->passwd, PASSWORD))
{
//认证失败 401
return 401;
}
return 0;
}
int HttpGetHandler(struct soap* soap)
{
//用于简单认证,选加
if (CheckAuthorization(soap))
{//认证失败
return 401;
}
//
fprintf(stderr, "HttpGetHandler!\n");
//返回一个html
soap_response(soap, SOAP_HTML);
soap_send(soap, "<html>HttpGetHandler</html>");
soap_end_send(soap);
return SOAP_OK;
}
int HttpPostHandler(struct soap* soap)
{
//用于简单认证,选加
if (CheckAuthorization(soap))
{//认证失败
return 401;
}
//
fprintf(stderr, "HttpPostHandler!\n");
//返回一个html
soap_response(soap, SOAP_HTML);
soap_send(soap, "<html>HttpPostHandler</html>");
soap_end_send(soap);
return SOAP_OK;
}
//RESTful不需要使用此函数,但需要实现它。
int ns__test(struct soap* soap)
{
return SOAP_NO_METHOD;
}
效果如下图:
使用gSoap可以很容易的搭建起Webservice,也可以很容易的在多个平台上使用。