完全无关,但您的配置格式确实如此要求为分层格式,如JSON或XML。
为了好玩,我重构该样本使用XML:
<?xml version="1.0"?>
<CONFIG>
<DATABASE>
<HOST>localhost</HOST>
<USER>root</USER>
<PASS>youbet</PASS>
<SCHEMA>my_game</SCHEMA>
</DATABASE>
<GAME_SERVER>
<SERVER>
<CHANNEL>
<IP>127.0.0.1</IP>
<PORT>6767</PORT>
</CHANNEL>
<CHANNEL>
<IP>127.0.0.2</IP>
<PORT>6868</PORT>
</CHANNEL>
</SERVER>
</GAME_SERVER>
</CONFIG>
,你可以用下面的代码片段阅读:
boost::property_tree::ptree pt;
boost::property_tree::read_xml("game_server_config.xml", pt);
if (auto dbconfig = pt.get_child_optional("CONFIG.DATABASE")) {
database.host = dbconfig->get<std::string>("HOST");
database.username = dbconfig->get<std::string>("USER");
database.password = dbconfig->get<std::string>("PASS");
database.schema = dbconfig->get<std::string>("SCHEMA");
}
和服务器/渠道:
for (auto& serverconfig: pt.get_child("CONFIG.GAME_SERVER")) {
if ("SERVER" != serverconfig.first)
continue;
servers.emplace_back();
auto& current_server = servers.back();
for (auto& channelconfig: serverconfig.second) {
if ("CHANNEL" != channelconfig.first)
continue;
Canal CanalTemp;
CanalTemp.ip = channelconfig.second.get<std::string>("IP");
CanalTemp.port = channelconfig.second.get<short>("PORT");
tcp::endpoint endpoint(boost::asio::ip::address::from_string(CanalTemp.ip), CanalTemp.port);
current_server.emplace_back(io_service, Database_ptr, endpoint);
}
}
查看一下Live On Coliru以及:)
#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/bind.hpp>
#include <iostream>
// for iterator and reference stability (see:
// http://stackoverflow.com/questions/6438086/iterator-invalidation-rules)
#include <list>
using tcp = boost::asio::ip::tcp;
struct Canal {
std::string ip;
int port;
};
struct Database {
std::string host, username, password, schema;
};
struct TDatabase {
TDatabase(Database config) : details(config) {}
void Connect() {
std::cout
<< "Connecting to fake database " << details.host << "/" << details.schema
<< " with user " << details.username << " and password '" << std::string(details.password.size(), '*') << "'\n";
}
private:
Database details;
};
struct TSession : std::enable_shared_from_this<TSession> {
TSession(boost::asio::io_service& svc, std::shared_ptr<TDatabase> db) :
_svc(svc), _socket(_svc), _db(db) {}
tcp::socket& Socket() { return _socket; }
void Start() {
boost::asio::async_read(_socket, _sb,
boost::bind(&TSession::HandleReceived, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void HandleReceived(boost::system::error_code ec, size_t bytes_transferred) {
if (!ec || boost::asio::error::eof == ec) {
std::cout << "Received from " << _socket.remote_endpoint() << ": '" << &_sb << "'\n";
} else
{
std::cout << "Error reading from peer: " << ec.message() << "\n";
}
}
private:
boost::asio::io_service& _svc;
tcp::socket _socket;
std::shared_ptr<TDatabase> _db;
boost::asio::streambuf _sb;
};
struct TServer {
tcp::acceptor acceptor;
std::shared_ptr<TDatabase> database;
TServer(boost::asio::io_service &io_service, std::shared_ptr<TDatabase> database, const boost::asio::ip::tcp::endpoint &endpoint)
: acceptor(io_service, endpoint), database(database)
{
Accept_Connection();
}
void Accept_Connection() {
auto Connection = std::make_shared<TSession>(acceptor.get_io_service(), database);
acceptor.async_accept(Connection->Socket(),
boost::bind(&TServer::Handle_Connection, this, Connection, boost::asio::placeholders::error));
}
void Handle_Connection(std::shared_ptr<TSession> Connection, const boost::system::error_code &error) {
if (!error) {
Connection->Start();
Accept_Connection();
} else
std::cout << "Error: " << error.message() << "\n";
}
};
//#include "TServer.h"
//#include "TDatabase.h"
//#include "Includes.h"
//#include "Structures.h"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
int main() {
try {
std::cout << "========================================" << std::endl
<< "= Game Server v1.0 by Gravity1 =" << std::endl
<< "========================================" << std::endl;
boost::asio::io_service io_service;
Database database;
std::list<std::list<TServer> > servers;
srand(time(0));
boost::property_tree::ptree pt;
boost::property_tree::read_xml("game_server_config.xml", pt);
if (auto dbconfig = pt.get_child_optional("CONFIG.DATABASE")) {
database.host = dbconfig->get<std::string>("HOST");
database.username = dbconfig->get<std::string>("USER");
database.password = dbconfig->get<std::string>("PASS");
database.schema = dbconfig->get<std::string>("SCHEMA");
}
std::shared_ptr<TDatabase> Database_ptr = std::make_shared<TDatabase>(database);
Database_ptr->Connect();
for (auto& serverconfig: pt.get_child("CONFIG.GAME_SERVER")) {
if ("SERVER" != serverconfig.first)
continue;
servers.emplace_back();
auto& current_server = servers.back();
for (auto& channelconfig: serverconfig.second) {
if ("CHANNEL" != channelconfig.first)
continue;
Canal CanalTemp;
CanalTemp.ip = channelconfig.second.get<std::string>("IP");
CanalTemp.port = channelconfig.second.get<short>("PORT");
tcp::endpoint endpoint(boost::asio::ip::address::from_string(CanalTemp.ip), CanalTemp.port);
current_server.emplace_back(io_service, Database_ptr, endpoint);
}
}
io_service.run();
}
catch (std::exception &e) {
std::cerr << e.what() << std::endl;
}
std::cin.get();
}
打印
========================================
= Game Server v1.0 by Gravity1 =
========================================
Connecting to fake database localhost/my_game with user root and password '******'
Received from 127.0.0.1:55712: 'hello channel
'
Received from 127.0.0.1:37987: 'hello OTHER channel
'
Received from 127.0.0.1:55714: 'hello channel
'
Received from 127.0.0.1:37989: 'hello OTHER channel
'
Received from 127.0.0.1:55716: 'hello channel
'
等
也许你忘了打电话'acceptor.listen()'? – PSIAlt
https://www.livecoding.tv/sehe/([experiment](http://chat.stackoverflow.com/transcript/10?m=24182469#24182469)) – sehe