天天看點

使用boost::asio庫實作多個子程序監聽同一個端口

class session_http {
public:
	session_http(boost::asio::io_context &io) : socket_(io) {};
	void run(boost::asio::yield_context yield) {
	boost::system::error_code ec;
	boost::beast::flat_buffer buffer;
	while (true) {
		// Read a request
		boost::beast::http::async_read(socket_, buffer, req_, yield[ec]);
		if(ec) {
			BOOST_LOG_TRIVIAL(error) << "Read fail: " << ec.message();
			break;
		}
		BOOST_LOG_TRIVIAL(debug) << "Read: " << req_;
		BOOST_LOG_TRIVIAL(info) << "Read: " << req_.method_string() << " " << req_.target();

		send_response(yield, "success");
		if(req_.need_eof())	{// ture means Connection: close
			// This means we should close the connection, usually because
			// the response indicated the "Connection: close" semantic.
			break;
		}
		req_.body().clear();
	}
    // Send a TCP shutdown
    socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
}

private:
    void send_response(boost::asio::yield_context yield, const std::string &body) {
	boost::system::error_code ec;
	// Send the response
	boost::beast::http::response<boost::beast::http::string_body> 
    res{boost::beast::http::status::ok, req_.version()};
	res.set(boost::beast::http::field::server, "Server");
	res.set(boost::beast::http::field::content_type, "text/json");
	res.body() = body;
	res.content_length(body.length());
	res.keep_alive(req_.keep_alive());
	BOOST_LOG_TRIVIAL(debug) << "Write: " << res;
	BOOST_LOG_TRIVIAL(info) << "Write: " << res.result_int() << " " << body.length() << " " << res.body();
	boost::beast::http::async_write(socket_, res, yield[ec]);
	if(ec) {
		BOOST_LOG_TRIVIAL(error) << "Write fail: " << ec.message();
	}
}

	boost::asio::ip::tcp::socket socket_;
	boost::beast::http::request<boost::beast::http::string_body> req_;

	friend class server_http;
};

class server_http {
public:
	server_http(boost::asio::io_context &io) : acceptor_(io) {};
	void init() {
	boost::system::error_code ec;
	boost::asio::ip::tcp::endpoint addr(boost::asio::ip::tcp::v6(), 8888);
	acceptor_.open(addr.protocol());
	acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), ec);
	acceptor_.bind(addr);
	acceptor_.listen(2048);
};
	void run(boost::asio::yield_context yield) {
	boost::system::error_code ec;
	while (true) {
		auto session = std::make_shared<session_http>(acceptor_.get_executor().context());
		acceptor_.async_accept(session->socket_, yield[ec]);
		if (ec) {
			BOOST_LOG_TRIVIAL(error) << "Accep error: " << ec.message();
			continue;
		}
		BOOST_LOG_TRIVIAL(debug) << "Accep request " << session->socket_.remote_endpoint(ec);
		if (ec) {
			BOOST_LOG_TRIVIAL(error) << "remote_endpoint http error: " << ec.message();
			continue;
		}
		// 在單獨的協程當中運作 session
		boost::asio::spawn(acceptor_.get_executor(), std::bind(&session_http::run, session, std::placeholders::_1));
	}
};

	boost::asio::ip::tcp::acceptor acceptor_;
private:
};

void run(boost::asio::io_context& io);
#include<sys/types.h>
#include<sys/wait.h>
int main(int argc, char* argv[]) {
	// 基礎的運作上下文
	boost::asio::io_context io;

	// http服務
	server_http http(io);
	http.init();
//	boost::asio::spawn(io, std::bind(&server_http::run, &http, std::placeholders::_1));

	pid_t p;
	for (int i = 0; i < 4; i++) {
		p = fork();
		//子程序退出循環,不再建立子程序,全部由主程序建立子程序,這裡是關鍵所在
		if (p==0 || p==-1) {
			break;
		}
	}
	if (p == -1) {
		std::cout << "fail to fork!" << std::endl;
		return 0;
	} else if (p == 0) {
		//子程序處理邏輯
		// 基礎的運作上下文
		boost::asio::io_context io;

		server_http http_child(io);
		boost::asio::ip::tcp::endpoint addr(boost::asio::ip::tcp::v6(), 8888);
		http_child.acceptor_.assign(addr.protocol(), http.acceptor_.native_handle() );
		boost::asio::spawn(io, std::bind(&server_http::run, &http_child, std::placeholders::_1));

		std::cout << "child:" << getpid() << std::endl;
		std::vector<std::thread> v;
		for(auto i = 4; i > 0; --i) {
			v.emplace_back([&] {run(std::ref(io));});
		}

		for(int i=0;i<4;++i) {
			v[i].join();
		}
	} else {
		// 父程序
		std::cout << "main:" << getpid() << std::endl;
		waitpid(p, NULL, 0);
	}
}
void run(boost::asio::io_context& io) {
	io.run();
}
           

多個程序共同監聽同一端口,效率和同一個程序用協程方式處理一樣,多程序并沒有提高tps