目前协程很火,于是决定搞一个框架试试,下面的代码很短,不过麻雀虽小,五脏俱全。目前支持tbus,配上boost::asio,可以很容易的支持tcp,udp,异步文件读写等操作。
附linux下编译指令:
g++ server.cpp -I$(BOOST_ROOT) -o server \
$(BOOST_ROOT)/stage/lib/libboost_coroutine.a\
$(BOOST_ROOT)/stage/lib/libboost_context.a\
$(BOOST_ROOT)/stage/lib/libboost_system.a\
$(BOOST_ROOT)/stage/lib/libboost_thread.a -lpthread -lrt
#include <boost/asio.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <boost/shared_ptr.hpp>
namespace ba = boost::asio;
class fake_tbus
{
public:
fake_tbus()
:m_trans_id(0)
,m_msg("initial request")
{}
void tbus_send(int trans_id, std::string buf)
{
m_trans_id = trans_id;
m_msg = buf;
std::cout << "tbus_send: " << trans_id << ": " << m_msg << std::endl;
}
std::string tbus_recv(int& trans_id)
{
trans_id = m_trans_id;
std::cout << "tbus_recv: " << trans_id << ": " << m_msg << std::endl;
return m_msg;
}
private:
int m_trans_id;
std::string m_msg;
};
class server
{
public:
typedef boost::coroutines::asymmetric_coroutine<std::string>::push_type push_type;
typedef boost::coroutines::asymmetric_coroutine<std::string>::pull_type pull_type;
typedef boost::shared_ptr<push_type> push_type_ptr;
typedef std::map<int, push_type_ptr> coroutine_map_t;;
server()
:m_stop(false)
{
}
void run()
{
int global_trans_id = 0;
while (!m_stop)
{
int tbus_trans_id = 0;
std::string buf = m_tbus.tbus_recv(tbus_trans_id);
push_type_ptr p_push;
// this is an new request, so we create a new coroutine.
if (tbus_trans_id == 0)
{
global_trans_id++;
p_push.reset(new push_type(boost::bind(&server::tbus_handler, this, global_trans_id, _1)));
m_coroutines.insert(std::make_pair(global_trans_id, p_push));
tbus_trans_id = global_trans_id;
}
// this should be in a transaction, find the coroutine dealing with it.
else
{
coroutine_map_t::iterator it = m_coroutines.find(tbus_trans_id);
if (it != m_coroutines.end())
{
p_push = it->second;
}
}
if (p_push)
{
// to the next step.
bool has_next = (*p_push)(buf);
if (!has_next)
{
// if coroutine has returnd, finish it.
m_coroutines.erase(tbus_trans_id);
}
}
boost::this_thread::sleep_for(boost::chrono::seconds(1));
}
}
// our handler function.
void tbus_handler(int trans_id, pull_type& pull)
{
std::string req = get_request(pull);
std::cout << "tbus_handler req: " << req << std::endl;
std::string res = yield_async_send(trans_id, pull, "hello");
std::cout << "tbus_handler res1: " << res << std::endl;
res = yield_async_send(trans_id, pull, "world");
std::cout << "tbus_handler res2: " << res << std::endl;
}
std::string yield_async_send(int trans_id, pull_type& pull, std::string buf)
{
m_tbus.tbus_send(trans_id, buf);
pull();
return pull.get();
}
std::string get_request(pull_type& pull)
{
return pull.get();
}
coroutine_map_t m_coroutines;
bool m_stop;
fake_tbus m_tbus;
};
int main(int argc, char* argv[])
{
server s;
s.run();
return 0;
}
/*
输出:
tbus_recv: 0: initial request
tbus_handler req: initial request
tbus_send: 1: hello
tbus_recv: 1: hello
tbus_handler res1: hello
tbus_send: 1: world
tbus_recv: 1: world
tbus_handler res2: world
tbus_recv: 1: world
tbus_recv: 1: world
tbus_recv: 1: world
tbus_recv: 1: world
tbus_recv: 1: world
*/