Перевел пример простого сервера на stackful coroutines (пока без обработки ошибок и завершения соединения)
This commit is contained in:
parent
efe4b8f50f
commit
99f137ca25
@ -38,7 +38,7 @@ endif()
|
|||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
boost
|
boost
|
||||||
URL http://switch.dl.sourceforge.net/project/boost/boost/${boost_version}/boost_${boost_version_underscored}.zip
|
URL http://switch.dl.sourceforge.net/project/boost/boost/${boost_version}/boost_${boost_version_underscored}.zip
|
||||||
CONFIGURE_COMMAND ./bootstrap.sh --with-libraries=coroutine
|
CONFIGURE_COMMAND ./bootstrap.sh --with-libraries=coroutine,thread
|
||||||
BUILD_COMMAND ./b2 --ignore-site-config --stagedir=${CMAKE_SOURCE_DIR} link=static threading=multi cxxflags=-std=c++11 ${boost_build_type}
|
BUILD_COMMAND ./b2 --ignore-site-config --stagedir=${CMAKE_SOURCE_DIR} link=static threading=multi cxxflags=-std=c++11 ${boost_build_type}
|
||||||
BUILD_IN_SOURCE 1
|
BUILD_IN_SOURCE 1
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
@ -62,7 +62,7 @@ project(${TEST_SERVER_PROJECT_NAME} CXX)
|
|||||||
aux_source_directory(${SRC_DIR}/server TEST_SERVER_SRC)
|
aux_source_directory(${SRC_DIR}/server TEST_SERVER_SRC)
|
||||||
add_executable(${TEST_SERVER_PROJECT_NAME} ${TEST_SERVER_SRC})
|
add_executable(${TEST_SERVER_PROJECT_NAME} ${TEST_SERVER_SRC})
|
||||||
add_dependencies(${TEST_SERVER_PROJECT_NAME} boost cpputil)
|
add_dependencies(${TEST_SERVER_PROJECT_NAME} boost cpputil)
|
||||||
target_link_libraries(${TEST_SERVER_PROJECT_NAME} cpputil ${CMAKE_SOURCE_DIR}/lib/libboost_system.a ${CMAKE_SOURCE_DIR}/lib/libboost_coroutine.a)
|
target_link_libraries(${TEST_SERVER_PROJECT_NAME} cpputil ${CMAKE_SOURCE_DIR}/lib/libboost_system.a ${CMAKE_SOURCE_DIR}/lib/libboost_thread.a ${CMAKE_SOURCE_DIR}/lib/libboost_coroutine.a ${CMAKE_SOURCE_DIR}/lib/libboost_context.a)
|
||||||
|
|
||||||
install(TARGETS ${TEST_PROJECT_NAME}
|
install(TARGETS ${TEST_PROJECT_NAME}
|
||||||
RUNTIME DESTINATION bin
|
RUNTIME DESTINATION bin
|
||||||
|
|||||||
@ -1,10 +1,35 @@
|
|||||||
#include "server.h"
|
#include "session.h"
|
||||||
|
|
||||||
|
#include <boost/asio/spawn.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
using tcp = boost::asio::ip::tcp;
|
||||||
|
|
||||||
|
void start_server(std::string address, std::string port)
|
||||||
|
{
|
||||||
|
boost::asio::io_service io_service;
|
||||||
|
tcp::resolver resolver(io_service);
|
||||||
|
tcp::resolver::query query(address, port);
|
||||||
|
tcp::acceptor acceptor(io_service, *resolver.resolve(query));
|
||||||
|
|
||||||
|
boost::asio::spawn(io_service, [&](boost::asio::yield_context yield){
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
session* s = new session(io_service);
|
||||||
|
acceptor.async_accept(s->socket(), yield);
|
||||||
|
s->start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
io_service.run();
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
server srv("0.0.0.0", "12345");
|
// server srv("0.0.0.0", "12345");
|
||||||
srv.run();
|
// srv.run();
|
||||||
|
|
||||||
|
start_server("0.0.0.0", "12345");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1,41 +0,0 @@
|
|||||||
#include "server.h"
|
|
||||||
#include <boost/asio/yield.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
server::server(const std::string& address, const std::string& port)
|
|
||||||
{
|
|
||||||
tcp::resolver resolver(_io_service);
|
|
||||||
tcp::resolver::query query(address, port);
|
|
||||||
_acceptor = new tcp::acceptor(_io_service, *resolver.resolve(query));
|
|
||||||
}
|
|
||||||
|
|
||||||
void server::run()
|
|
||||||
{
|
|
||||||
accept();
|
|
||||||
_io_service.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
void server::accept(boost::system::error_code ec)
|
|
||||||
{
|
|
||||||
if(!ec)
|
|
||||||
{
|
|
||||||
reenter(this) for(;;)
|
|
||||||
{
|
|
||||||
_session = new session(_io_service);
|
|
||||||
yield _acceptor->async_accept(_session->_socket, std::bind(&server::accept, this, std::placeholders::_1));
|
|
||||||
std::cout << "new connection started" << std::endl;
|
|
||||||
_session->start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout << "error: " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server::~server() {
|
|
||||||
if(_socket) delete _socket;
|
|
||||||
if(_acceptor) delete _acceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <boost/asio/unyield.hpp>
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
#ifndef _SERVER_H_
|
|
||||||
#define _SERVER_H_
|
|
||||||
|
|
||||||
#include "session.h"
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
|
|
||||||
class server: boost::asio::coroutine
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
typedef boost::asio::ip::tcp tcp;
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::asio::io_service _io_service;
|
|
||||||
tcp::acceptor* _acceptor;
|
|
||||||
tcp::socket* _socket;
|
|
||||||
session* _session;
|
|
||||||
|
|
||||||
public:
|
|
||||||
server() = delete ;
|
|
||||||
server(server& srv) = delete;
|
|
||||||
server(const std::string& address, const std::string& port);
|
|
||||||
void run();
|
|
||||||
~server();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void accept(boost::system::error_code ec = boost::system::error_code());
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _SERVER_H_
|
|
||||||
@ -1,37 +1,29 @@
|
|||||||
#include "session.h"
|
#include "session.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <boost/asio/yield.hpp>
|
#include <boost/asio/spawn.hpp>
|
||||||
|
|
||||||
session::session(boost::asio::io_service &io_service): boost::asio::coroutine(), _socket(io_service)
|
session::session(boost::asio::io_service &io_service): boost::asio::coroutine(), _socket(io_service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void session::start(boost::system::error_code ec, std::size_t bytes_transferred)
|
void session::start()
|
||||||
{
|
{
|
||||||
if(!ec)
|
boost::asio::spawn(_socket.get_io_service(), [this](boost::asio::yield_context yield){
|
||||||
|
for(;;)
|
||||||
{
|
{
|
||||||
reenter(this) for(;;) // псевдолинейный код
|
std::size_t bytes = _socket.async_read_some(boost::asio::buffer(_data, 128), yield);
|
||||||
{
|
|
||||||
std::memset(_data, 0, 128);
|
|
||||||
yield _socket.async_read_some(boost::asio::buffer(_data, 128), std::bind(&session::start, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
|
|
||||||
yield _fut = call_async<int>([this]{
|
int n = async_call<int>([this]{
|
||||||
int n = std::atoi(_data);
|
int n = std::atoi(_data);
|
||||||
return n*n;
|
return n*n;
|
||||||
|
}, yield);
|
||||||
|
|
||||||
|
_socket.async_write_some(boost::asio::buffer(std::to_string(n) + "\n"), yield);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
yield {
|
boost::asio::ip::tcp::socket& session::socket()
|
||||||
std::string res = std::to_string(_fut.get()) + "\n";
|
|
||||||
_socket.async_write_some(boost::asio::buffer(res), std::bind(&session::start, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
std::cout << "error: " << ec.message() << std::endl;
|
return _socket;
|
||||||
delete this;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#include <boost/asio/unyield.hpp>
|
|
||||||
|
|||||||
@ -8,7 +8,6 @@ class session: boost::asio::coroutine
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
typedef boost::asio::ip::tcp tcp;
|
typedef boost::asio::ip::tcp tcp;
|
||||||
friend class server;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tcp::socket _socket;
|
tcp::socket _socket;
|
||||||
@ -22,17 +21,21 @@ public:
|
|||||||
session() = delete;
|
session() = delete;
|
||||||
session(session&) = delete;
|
session(session&) = delete;
|
||||||
session(boost::asio::io_service& io_service);
|
session(boost::asio::io_service& io_service);
|
||||||
void start(boost::system::error_code ec = boost::system::error_code(), std::size_t bytes_transferred = 0);
|
void start();
|
||||||
|
|
||||||
template <typename R> std::future<R> call_async(std::function<R()> func)
|
template <typename R, typename CompletionToken> R async_call(std::function<R()> func, CompletionToken&& token)
|
||||||
{
|
{
|
||||||
return _pool.add_task<R>([this, &func]{
|
typename boost::asio::handler_type<CompletionToken, void(R)>::type handler(std::forward<CompletionToken>(token));
|
||||||
R result = func();
|
boost::asio::async_result<decltype(handler)> result(handler);
|
||||||
_socket.get_io_service().dispatch(std::bind(&session::start, this, boost::system::error_code(), 0));
|
|
||||||
return result;
|
_pool.add_task<void>([this, handler, &func]{
|
||||||
|
_socket.get_io_service().dispatch(std::bind(handler, func()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::asio::ip::tcp::socket& socket();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _SESSION_H_
|
#endif // _SESSION_H_
|
||||||
Loading…
Reference in New Issue
Block a user