C++ 使用Boost.asio库实现HTTP服务端,讲解、并附带VS2015工程可直接编译运行

前言

  最近学习Boost.aiso库,把官网的HTTP 服务端的例子给实现了一下。
  官网链接:https://www.boost.org/doc/libs/1_67_0/doc/html/boost_asio/examples/cpp11_examples.html
  笔者建了一个VS工程,并把相关的头文件和依赖库给整合了进去,下载下来之后可以直接在Release X64下编译执行。
  下载链接: Boost.Aiso实现Http服务端,VS2015工程可直接编译运行
执行结果如图所示:
在这里插入图片描述
PS: 上面的文件下载会需要C币,如果你没有C币的话可以留言,我发你邮箱

讲解

下面将从整个程序一步一步解析HTTP服务端是如何接受并处理请求的。

1、main函数

  main函数很简单,就是启动了一个server实例、并运行。

int main(int argc, char* argv[])
{
	try
	{
		// Check command line arguments.
		//if (argc != 4)
		//{
		//	std::cerr << "Usage: http_server <address> <port> <doc_root>\n";
		//	std::cerr << "  For IPv4, try:\n";
		//	std::cerr << "    receiver 0.0.0.0 80 .\n";
		//	std::cerr << "  For IPv6, try:\n";
		//	std::cerr << "    receiver 0::0 80 .\n";
		//	return 1;
		//}

		//官网的例子是通过命令行传参的,这里为方便,直接在代码中写死

		// Initialise the server.
		std::string ip_address = "0.0.0.0";
		std::string port = "8080";
		std::string doc_root = "../../../docs";
		http::server::server s(ip_address, port, doc_root);

		// Run the server until stopped.
		s.run();
	}
	catch (std::exception& e)
	{
		std::cerr << "exception: " << e.what() << "\n";
	}

	return 0;
}

2、server构造函数

  server构造函数中主要就是构造:

  • boost::asio::io_service对象,用于执行异步操作
  • boost::asio::signal_set对象,用于接收外部信号,比如ctrl+ckill,收到这些信号就会清理资源并退出程序
  • boost::asio::ip::tcp::acceptor对象,用于监听连接
  • connection_manager对象,用于管理连接
  • boost::asio::ip::tcp::socket对象,是一个流,接收到的socket报文都会放进这个对象里
  • request_handler,用于处理请求
    此外,在构造函数体内,还解析了监听地址和端口,并开始监听。最后,调用do_accept();来处理接收到的请求
		server::server(const std::string& address, const std::string& port,
			const std::string& doc_root)
			: io_service_(),
			signals_(io_service_),
			acceptor_(io_service_),
			connection_manager_(),
			socket_(io_service_),
			request_handler_(doc_root)
		{
			// Register to handle the signals that indicate when the server should exit.
			// It is safe to register for the same signal multiple times in a program,
			// provided all registration for the specified signal is made through Asio.
			signals_.add(SIGINT);
			signals_.add(SIGTERM);
#if defined(SIGQUIT)
			signals_.add(SIGQUIT);
#endif // defined(SIGQUIT)

			do_await_stop();

			// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
			boost::asio::ip::tcp::resolver resolver(io_service_);
			boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve({ address, port });
			acceptor_.open(endpoint.protocol());
			acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
			acceptor_.bind(endpoint);
			acceptor_.listen();

			do_accept();
		}

3、server::do_accept

这步,是将收到的socket流通过异步的方式传给connection_manager_.start。异步就意味着,这一步是不阻塞的,会立马返回。当有新的socket报文来的时候,才会调用后面的操作。

void server::do_accept()
		{
			acceptor_.async_accept(socket_,
				[this](boost::system::error_code ec)
			{
				// Check whether the server was stopped by a signal before this
				// completion handler had a chance to run.
				if (!acceptor_.is_open())
				{
					return;
				}

				if (!ec)
				{
					connection_manager_.start(std::make_shared<connection>(
						std::move(socket_), connection_manager_, request_handler_));
				}

				do_accept();
			});
		}

4、connection_manager::start

上一部中构造了一个connection对象,并将只能指针传进来。这一步中将只能connection对象的智能指针放进set里,用于连接管理。然后调用connection::start进行do_read

		void connection_manager::start(connection_ptr c)
		{
			connections_.insert(c);
			c->start();
		}
			void connection::start()
		{
			do_read();
		}

5、connection::do_read

  将socket中的字节流读入buffer中,然后调用request_parser_.parse一个字节一个字节地解析buffer中的数据,parse的过程比较麻烦但是比较容易,就是普通的字符处理,最终构造出buffer中的数据解析成一个request对象。
  然后,调用request_handler_.handle_request处理request,并返回reply_,其过程就是读取request中要请求的文件,然后读取文件并将文件内容存在reply中。
  最后,调用do_write()

6、connection::do_write

  这一步就是将上一步得到的reply_写进socket流中。最终socket流会返回给客户端。

  至此,这个简单的http服务端接收请求->解析请求->处理请求->构造响应->发送响应的流程就走完了。但是这个Demo中的很多思想还是很值以后继续慢慢学习的。

评论 89
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值