Libboost ASIO. Simple asynchronous client server

I am trying to implement a simple client / server in ASIO.

I need the following on the server:

onConnect()
onDisconnect()
onMessageRecieved(char* data)
sendMessage(char* data)

and on the client side:

onConnect()
onDisconnect()
onMessageRecieved(char* data)
sendMessage(char* data)

I did not understand that everything would be so complicated.

Here's a simple echo server I'm working on:

 #include <cstdlib> #include <iostream> #include <boost/bind.hpp> #include <boost/asio.hpp> using boost::asio::ip::tcp; class session { public: session(boost::asio::io_service& io_service) : socket_(io_service) { } tcp::socket& socket() { return socket_; } void start() { socket_.async_read_some(boost::asio::buffer(data_, max_length), boost::bind(&session::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void handle_read(const boost::system::error_code& error, size_t bytes_transferred) { if (!error) { boost::asio::async_write(socket_, boost::asio::buffer(data_, bytes_transferred), boost::bind(&session::handle_write, this, boost::asio::placeholders::error)); } else { delete this; } } void handle_write(const boost::system::error_code& error) { if (!error) { socket_.async_read_some(boost::asio::buffer(data_, max_length), boost::bind(&session::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else { delete this; } } private: tcp::socket socket_; enum { max_length = 1024 }; char data_[max_length]; }; class server { public: server(boost::asio::io_service& io_service, short port) : io_service_(io_service), acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) { session* new_session = new session(io_service_); acceptor_.async_accept(new_session->socket(), boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error)); } void handle_accept(session* new_session, const boost::system::error_code& error) { if (!error) { new_session->start(); new_session = new session(io_service_); acceptor_.async_accept(new_session->socket(), boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error)); } else { delete new_session; } } private: boost::asio::io_service& io_service_; tcp::acceptor acceptor_; }; int main(int argc, char* argv[]) { try { if (argc != 2) { std::cerr << "Usage: async_tcp_echo_server <port>\n"; return 1; } boost::asio::io_service io_service; using namespace std; // For atoi. server s(io_service, atoi(argv[1])); io_service.run(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } 

I can use telnet on this server and it all repeats.

Now I would like to complete this code in onConnect() , onDisconnect() , onMessageReceived(char* data) , etc. Just like this is done in Node.js!

Does anyone have directions in this regard?

+6
source share
1 answer
  • onMessageReceived() can be called from handle_read .
  • onConnect() can be called from start .
  • onDisconnect() can be called in the session class destructor.

For questions about generosity:

io_service.run() can be placed in its own thread.

In accordance with the documentation

Certain guarantees are defined when the handler is called, in particular, that the handler can only be called from the thread that currently calls run () on the corresponding io_service object.

Asynchronous sending and receiving can be handled by this single thread. This simplifies thread safety since all callbacks will be executed sequentially. This is probably the easiest way to use boost asio.

For calls coming from outside the run() thread, you can schedule a callback (for example, deadline_timer ), from outside thread "for an immediate call, to simplify thread safety handling. For example.

  boost::asio::deadline_timer timer(io_service); timer.expires_from_now(boost::posix_time::seconds(0)); timer.async_wait(boost::bind(&MyClass::MyCallback, this, boost::asio::placeholders::error); 

The io_service object will call the handler for you in thread safe mode as soon as it has a chance. Thus, your asio code can behave as if there was only one thread in the entire system.

If you need several or more threads (for example, use a multi-core processor), you can call run() for several threads. Handlers must be re-involved. You can also use strand for certain operations.

Otherwise, thread safety rules apply.

+3
source

Source: https://habr.com/ru/post/894289/


All Articles