The mainstream asynchronous IO in client applications is similar to that in synchronous client applications. The difference is that Boost. Asio is located in the middle of async_read and async_write requests each time. The mainstream asynchronous I/O in client applications is similar to that in synchronous client applications. The difference is that Boost. Asio is located in the middle of async_read and async_write requests each time. The first case is what I have implemented in Chapter 4 client and server. You should remember that when each asynchronous operation ends, I start another asynchronous operation so that the service. run () method will not end. To adapt to the second scenario, you need to use the following code snippet:
void on_connect() { do_read();
} void do_read() {
async_read(sock_, buffer(read_buffer_), MEM_FN2(read_complete,_1,_2), MEM_FN2(on_read,_1,_2));
} void on_read(const error_code & err, size_t bytes) {
if ( err) stop(); if ( !started() ) return; std::string msg(read_buffer_, bytes); if ( msg.find("clients") == 0) on_clients(msg); else ...
} void on_clients(const std::string & msg) {
std::string clients = msg.substr(8); std::cout << username_ << ", new client list:" << clients ; do_write("clients ok\n");
}
Note that as long as we connect successfully, we will start to read data from the server. Every on _ [event] method will end us by writing a reply to the server. The good thing about asynchronous operations is that you can use Boost. Asio for management to combine I/O network operations with other asynchronous operations. Although its process is not as clear as the synchronization process, you can still imagine it in synchronous mode. Suppose you read files from a web server and save them to a database (asynchronously ). You can think of this process as a flowchart below:
Asynchronous I/O of the server-side application is now expected to display two common cases: Case 1 (pull) and Case 2 (push) the first case is also the asynchronous server that I implement in Chapter 4th client and server. At the end of each asynchronous operation, I will start another asynchronous operation, so that service. run () will not end for a long time. The cropped framework code is to be displayed. The following are all members of the talk_to_client class:
void start() { ...
do_read(); // first, we wait for client to login }
void on_read(const error_code & err, size_t bytes) { std::string msg(read_buffer_, bytes); if ( msg.find("login ") == 0) on_login(msg); else if ( msg.find("ping") == 0) on_ping();
Else ...}
void on_login(const std::string & msg) { std::istringstream in(msg); in >> username_ >> username_; do_write("login ok\n");
} void do_write(const std::string & msg) {
std::copy(msg.begin(), msg.end(), write_buffer_); sock_.async_write_some( buffer(write_buffer_, msg.size()),
MEM_FN2(on_write,_1,_2));
} void on_write(const error_code & err, size_t bytes) {
Do_read ();}
Simply put, we always wait for a read operation, and once it happens, we process it and return the result to the client. We can modify the above code to complete a push server.
void start() { ...
on_new_client_event(); }
void on_new_client_event() { std::ostringstream msg; msg << "client count " << clients.size(); for ( array::const_iterator b = clients.begin(), e = clients.
end(); (*b)->do_write(msg.str());
}
void on_read(const error_code & err, size_t bytes) { std::string msg(read_buffer_, bytes); // basically here, we only acknowledge // that our clients received our notifications
}void do_write(const std::string & msg) {
std::copy(msg.begin(), msg.end(), write_buffer_); sock_.async_write_some( buffer(write_buffer_, msg.size()),
MEM_FN2(on_write,_1,_2));
}void on_write(const error_code & err, size_t bytes) {
Do_read ();}
As long as one event occurs, we assume it is on_new_client_event, and all clients to be notified will be sent a message. When they reply, we simply think they have confirmed that they have received the event. Note that we will never use up waiting asynchronous operations (so service. run () will not end), because we have been waiting for a new client:
ip::tcp::acceptor acc(service, ip::tcp::endpoint(ip::tcp::v4(), 8001)); void handle_accept(talk_to_client::ptr client, const error_code & err) {
client->start(); talk_to_client::ptr new_client = talk_to_client::new_(); acc.async_accept(new_client->sock(), bind(handle_accept,new_
client,_1)); }