如何创建一个Http/WebServer简易服务器

本文介绍了如何使用libevent库创建一个简单的Http服务器以及使用gsoap生成WebServer服务端。在libevent实现的Http服务器中,通过evhttp内置服务器处理请求,而在gsoap实现的WebServer中,利用gsoap生成的服务端接口处理请求。两种方法都涉及服务器的启动、监听和响应。文章提供了详细的代码示例和步骤,适合初学者参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

项目与第三方系统进行可选的Http/WebServer通信,接口协议文档修改,由原先项目仅作为客户端向第三方系统发送请求,现新增加一个接口,需项目作为服务端接收第三方系统发送的请求并做出应答。
结合项目之前的实现方法:Http传输协议使用libcurl库做客户端、WebServer传输协议使用gsoap生成客户端
确定项目目前服务端的实现方法:Http使用libevent库做服务端、WebServer使用gsoap生成服务端


一、libevent实现Http简易服务器

1.libevent安装

具体安装方法优快云上有很多教程可自行寻找,本人是按照这个教程进行的windows下编译及使用libevent,但我当时按这个教程做,在*(4)使用VS命令提示工具编译:*这一步出现了几个小问题导致编译失败,后来查找解决办法才编译成功。
附官网下载链接:http://libevent.org/

2.实现Http简易服务器

首先在项目中新建一个HttpServer类,你可以在这个类的构造函数中直接开启服务器,也可以写一个StartServer接口在里面实现
在开始之前,HttpServer.cpp文件要加上以下头文件(最好全部加上,可能有一些对你来说是多余的)

#include <sys/types.h>  
#include <event2/event-config.h>  
#include <sys/stat.h>  
#ifndef WIN32  
#include <sys/queue.h>  
#include <unistd.h> 
#include <winsock2.h> 
#endif  
#include <time.h>  
#ifdef _EVENT_HAVE_SYS_TIME_H  
#include <sys/time.h>  
#endif  
#include <fcntl.h>  
#include <stdlib.h>  
#include <stdio.h>  
#include <string.h>  
#include <errno.h>  
#include <event2/event.h>  
#include <event2/event_struct.h>  
#include <event2/util.h> 
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <evhttp.h>

#include <signal.h>
#include <ctype.h>
 
#pragma comment (lib,"Iphlpapi.lib")
#include <assert.h>
#include <corecrt_io.h>

这里服务器使用libevent库内置的evhttp服务器,代码如下

//这个函数功能是处理接收到的请求并产生应答
void now_handler(struct evhttp_request *req, void *arg)
{
	struct evbuffer *buf;
	buf = evbuffer_new();

	//获取客户端请求的URI(使用evhttp_request_uri或直接req->uri)
	
	// 分析请求
	char *decode_uri = _strdup((char*)evhttp_request_uri(req));
	
	//获取POST方法的数据	也有获取GET数据的方法只是这里没用到													  
	char *post_data = (char *)EVBUFFER_DATA(req->input_buffer);
	char *result;

	//在这里通过消息机制将接收到的请求传出并阻塞,等待信息处理完成后往下走,如果处理逻辑简单可以直接在这里处理
	::SendMessage((HWND)hWndParent, nMsgType, (WPARAM)post_data, (LPARAM)&result);

	// 返回HTTP头部
	evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=UTF-8");
	evhttp_add_header(req->output_headers, "Server", "my_httpd");
	evhttp_add_header(req->output_headers, "Connection", "close");

	//这里给应答赋值的是消息处理结束之后对应产生的应答 有一个接口设置strReply,在消息接收方处理消息完成后调用
	result = const_cast<char*>(strReply.c_str());
	// 将要输出的值写入输出缓存
	evbuffer_add_printf(buf, "%s", result);
	// 输出
	evhttp_send_reply(req, HTTP_OK, "OK", buf);
	// 内存释放
	evbuffer_free(buf);
}
//开启服务器的接口 建议在项目中单独开启一个std::thread运行
//比如:m_thread = std::thread(&HttpServer::StartServer, this);
void HttpServer::StartServer()
{
	//使用libevent内置的evhttp服务器
	struct evhttp *httpd;

	event_init();
	//这里设置服务器的IP以及端口,如127.0.0.1 8080
	httpd = evhttp_start(m_strIpAddress.c_str(),m_nPort);

	/* Set a callback for requests to "/specific". */

	/* evhttp_set_cb(httpd, "/specific", another_handler, NULL); */

	/* Set a callback for all other requests. */
	//这里设置服务器接收到请求之后处理请求的函数
	evhttp_set_gencb(httpd, now_handler, NULL);
	//服务器挂起
	event_dispatch();

	/* Not reached in this code as it is now. */

	evhttp_free(httpd);
}

到这里你创建的服务器就开始运行了,接下来你可以在浏览器上输入网址例如http://127.0.0.1:8080/,就可以正常访问了。

二、gsoap实现WebServer简易服务器

1.准备工作

自己看的一个教程Gsoap使用精华总结
下载goap后解压,下载地址 https://sourceforge.net/projects/gsoap2/files/
在你的项目目录中新建一个WebServer的文件夹,在你解压后的D:\gsoap_2.8.122\gsoap-2.8\gsoap\bin目录下拷贝soapcpp2.exe和wsdl2h.exe文件到WebServer文件夹(建议再在D:\gsoap_2.8.122\gsoap-2.8\gsoap拷贝一个typemap.dat文件过去,否则后面会提示缺少这个文件,虽然貌似没有影响),再准备一个描述接口的.wsdl文件或者.h文件就可以生成服务器了,这里的例子可以看上面的教程。

2.实现WebServer简易服务器

打开cmd,cd到WebServer文件夹下
输入:Wsdl2h.exe -s xxx.wsdl (此时会生成xxx.h文件)
再输入:Soapcpp2 -S -i xxx.h(Soapcpp2 详细命令可以参考教程)
然后把生成的soapC.cpp、soapH.h、soapStub.h、stdsoap2.h、stdsoap2.cpp、soapxxxService.h、soapxxxService.cpp等文件加入到项目中,然后在soapxxxService.cpp实现增加的接口,例如

//函数功能根据请求应答
int xxxService::pushInfo(char * infoJson, char *& result)
{
	//根据接收到的数据patientinfoJson 返回
	m_strReply = ("222222333333");
	//这里发信号与Http服务器的处理方式一致
	::SendMessage(m_hWndParent, m_nMsgType, (WPARAM)infoJson, (LPARAM)result);
	result = const_cast<char*>(m_strReply.c_str());
	return SOAP_OK;
}

接下来添加一个WebServer类,里面调用到gsoap生成的服务器类,与Http服务器类似,你可以在这个类的构造函数中直接开启服务器,也可以写一个StartServer接口在里面实现,例如

int http_get(struct soap  *soap)
{
	FILE *fd = NULL;
	fopen_s(&fd, "E:\\AppHisCommunicate3\\AppHisCommunicate\\WebServer\\HisApp.wsdl", "rb");//open WSDL file to copy

	if (NULL == fd)
	{
		return 404;//return HTTP not found error
	}

	soap->http_content = "text/xml";  //HTTP header with text /xml content
	soap_response(soap, SOAP_FILE);

	while (1)
	{
		size_t r = fread(soap->tmpbuf, 1, sizeof(soap->tmpbuf), fd);
		if (!r)
		{
			break;
		}
		if (soap_send_raw(soap, soap->tmpbuf, r))
		{
			break; //cannot send, but little we can do about that
		}
	}
	fclose(fd);
	soap_end_send(soap);
	return SOAP_OK;
}
//开启服务器,建议在线程中使用
void WebServer::StartServer()
{
	if (nullptr == m_pService)
	{
		m_pService = new xxxService(m_soap);
		//这里是自己添加的接口,方便发送信号
		m_pService->SetParentHWnd(m_hWndParent,m_nMsgType);
		m_pService->fget = http_get;
		//绑定服务器的Ip和端口号,例如127.0.0.1 8090
		m_pService->bind(m_strIpAddress.c_str(), m_nPort, 100);//NULL,8090,100
		int socketid = 0;
		do
		{
			socketid = m_pService->accept();
			if (socketid < 0)
			{
				m_pService->soap_stream_fault(std::cerr);
			}
			else
			{
				char* strMsg;
				strMsg = ("accepted connection from IP=");
				std::cout << *strMsg << m_pService->ip << " " << socketid;
			}

			int s = m_pService->serve();
			if (s != 0)
			{
				m_pService->soap_stream_fault(std::cerr);
			}
		} while (1);

		m_pService->reset();
		m_pService->destroy();
	}
}

此时服务器已经开启,浏览器输入 http://127.0.0.1:8090/HisApp?wsdl 可访问
还可以下载soapUI工具进行测试,可以参考SoapUI使用教程
应当注意的是,当gsoap同时生成客户端和服务端时需要先生成服务器,再生成客户端(命令Soapcpp2 -C -i xxx.h)(保持命名空间一致,在两个不同的文件夹下生成,否则生成的同名文件会覆盖),然后合并几个共同的文件(soapC.cpp、soapH.h、soapStub.h等),可以使用WinMerge工具,这里还要注意合并的时候几个宏的值不要重复。对服务器和客户端的接口要求不同时可以使用不同的.wsdl文件各自生成。


总结

总而言之,现在的各种库已经使得构建一个服务器变得越来越简洁,但是要做到更多的服务器相关功能,还是需要继续学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值