Boost.asio C + + Network programming Translator (20)

Source: Internet
Author: User

Asynchronous service-sideThis chart is quite complex; from Boost.asio you can see 4 arrows pointing to On_accept,on_read,on_write and on_check_ping. It also means that you never know which asynchronous call is the next complete call, but you can be sure that it is one of these 4 operations. Now that we are asynchronous, we can continue to keep the single thread. Accepting client connections is the simplest part, as follows:
Ip::tcp::acceptor acceptor (Service, Ip::tcp::endpoint (Ip::tcp::v4 (),   8001));   void Handle_accept (talk_to_client::p TR Client, const Error_code & err)   {
       Client->start ();       Talk_to_client::p TR new_client = Talk_to_client::new_ ();       Acceptor.async_accept (New_client->sock (),
                             Boost::bind (handle_accept,new_client,_1));
   }   int main (int argc, char* argv[]) {
       Talk_to_client::p TR client = Talk_to_client::new_ ();       Acceptor.async_accept (Client->sock (), Boost::bind (handle_accept,client,_1));
    Service.run ();}
The code above will wait asynchronously for a new client connection (each new client connection will trigger another asynchronous wait operation). we need to monitor the client list changed event (a new client connection or a client disconnect) and then notify all clients when the event occurs. Therefore, we need to save an array of client connections, otherwise you do not need an array unless you need to know all the connected clients at some point.
Class Talk_to_client; typedef boost::shared_ptr<talk_to_client>   client_ptr;   typedef std::vector<client_ptr> Array;   Array clients;
the framework of the connection class is as follows:

Class Talk_to_client:public Boost::enable_shared_from_this<talk_to_

Client>

                        , boost::noncopyable {       talk_to_client () {...}
   Public:       typedef boost::system::error_code Error_code;       typedef boost::shared_ptr<talk_to_client> PTR;       void Start () {
           Started_ = true;           Clients.push_back (Shared_from_this ());           last_ping = boost::p osix_time::microsec_clock::local_time ();           Do_read (); First, we wait for the client to connect
       }       static ptr new_ () {ptr new_ (new talk_to_client); return new_;}       void Stop () {
           if (!started_) return;           Started_ = false;           Sock_.close ();           PTR self = shared_from_this ();           Array::iterator it = Std::find (Clients.begin (), Clients.end (),
   self);           Clients.erase (IT);
           Update_clients_changed ();       }
       BOOL Started () const {return started_;}       Ip::tcp::socket & Sock () {return sock_;}       std::string username () const {return username_;}       void Set_clients_changed () {clients_changed_ = true;}       ...
Private
       Ip::tcp::socket Sock_;       enum {max_msg = 1024x768};       Char read_buffer_[max_msg];       Char write_buffer_[max_msg];       BOOL Started_;       std::string username_;       Deadline_timer Timer_;       Boost::p osix_time::p time last_ping;       BOOL Clients_changed_;

};

I'll use talk_to_client or talk_to_server to invoke the connection class, so that you know what I'm talking about.
Now you need to use the previous code, which is the same as what we used in the client application. But we also have another stop () method, which is used to remove a client connection from the client array. The server continues to wait for the asynchronous read operation:
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 ("login") = = 0) on_login (msg);       else if (Msg.find ("ping") = = 0) on_ping ();       else if (Msg.find ("ask_clients") = = 0) on_clients ();
   }   void On_login (const std::string & msg) {
       Std::istringstream in (msg);       In >> username_ >> username_;       Do_write ("Login ok\n");       Update_clients_changed ();
   }   void On_ping () {
       Do_write (clients_changed_? "Ping client_list_changed\n": "Ping   ok\n");
       Clients_changed_ = false;   }
void On_clients () {
    std::string msg;
for (Array::const_iterator b =clients.begin (), e =clients.end (); b!   = e; ++b)
           msg + = (*b)->username () + "";       Do_write ("clients" + msg + "\ n");

}

This code is easy to understand, and one thing to note is that when a new client logs in, we call update_clients_changed (), and this method will flag clients_changed_ as true for all clients. Each request received by the server is replied in the correct manner, as follows:
void Do_ping () {do_write ("ping\n");}   void Do_ask_clients () {do_write ("ask_clients\n");}   void On_write (const Error_code & err, size_t bytes) {do_read ();}   void Do_read () {
       Async_read (sock_, buffer (read_buffer_),                   mem_fn2 (read_complete,_1,_2), mem_fn2 (on_read,_1,_2));
       Post_check_ping ();   }
   void Do_write (const std::string & msg) {       if (!started ()) return;       Std::copy (Msg.begin (), Msg.end (), write_buffer_);       Sock_.async_write_some (Buffer (Write_buffer_, msg.size ()),
                               MEM_FN2 (on_write,_1,_2));
   }   size_t Read_complete (const Boost::system::error_code & err, size_t   bytes) {
       ... as before   }
At the end of each write operation, the On_write () method is called, and this method triggers another asynchronous read operation, so that the "wait for request-reply request" loop is executed until the client disconnects or times out. Before each read operation begins, we wait 5 seconds asynchronously to see if the client has timed out. If it times out, we close its connection:
void On_check_ping () {       ptime now = Microsec_clock::local_time ();       if ((now-last_ping). Total_milliseconds () > 5000)
           Stop ();       last_ping = boost::p osix_time::microsec_clock::local_time ();
   }   void Post_check_ping () {
       Timer_.expires_from_now (boost::p osix_time::millisec (5000));
       Timer_.async_wait (MEM_FN (on_check_ping));   }
This is the implementation of the entire service side. You can run and let it work! In the code, I've shown you what we've learned in this chapter, and to make it easier to understand, I've stripped the code a little bit, for example, I haven't shown most of the console output, even though they exist in the code attached to the book. I suggest you run these examples yourself, because reading the code from start to finish will enhance your understanding of the application in this chapter. Summary we have learned how to write some basic client/server applications. We have avoided some low-level errors such as memory leaks and deadlocks. All encodings are framed so that you can extend them to your own needs. In the following chapters, we'll take a deeper look at the differences between synchronous programming and asynchronous programming using Boost.asio, and you'll learn how to embed your own asynchronous operations.




Boost.asio C + + Network programming Translator (20)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.