Boost.asio C + + Network programming translator (15)

Source: Internet
Author: User

PS: Last night, the account was stolen, good customer service attitude, today training all day, so now only released

echo Service Side/Client

In this chapter, we will implement a small client/server application, which may be the simplest client/server application you have ever written. This is the Echo application, where any content written by the client is echoed back to itself, and then the connected server is closed. This server can handle any number of clients. Each client connects and then sends a message. The server receives all hours and sends it back. After that, the server closes the connection. Therefore, each ECHO client connects to the server side, sends a message, and then reads the result returned by the service side, ensuring that it is the message it sends to the server, and then ends the session with the server. We first implement a synchronous application and then implement an asynchronous application so that you can easily compare them to save space, and some of the following code is clipped out. You can see all the code in the Code attached to the book. TCP Echo Server/Client for TCP, we need an extra guarantee; the end of a newline character (' \ n ') for each message. Writing a synchronous echo Server/client is very simple. We will show coding, such as synchronous client, a synchronous server, an asynchronous client and an asynchronous server.
TCP Synchronization Clientin most valuable cases, the client is usually simpler than the server-side encoding (because the server needs to handle multiple client requests). The following code shows an exception to this rule:size_t read_complete (char * buf, const Error_code & err, size_t bytes){if (err) return 0;bool found = Std::find (buf, buf + bytes, ' \ n ') < buf + bytes;//We read one by one until read to enter, do not cachereturn found 0:1;}void Sync_echo (std::string msg) {msg + = "\ n";Ip::tcp::socket Sock (service);Sock.connect (EP);sock.write_some (Buffer (msg));Char buf[1024];int bytes = Read (sock, buffer (BUF), Boost::bind (Read_complete,buf,_1,_2));std::string Copy (buf, bytes-1);msg = msg.substr (0, Msg.size ()-1);std::cout << "server echoed our" << msg << ":"<< (copy = msg?) "OK": "FAIL") << Std::endl;sock.close ();}int main (int argc, char* argv[]) {char* messages[] = {"John says hi", "so does James","Lucy just got Home", "Boost.asio is fun!", 0};Boost::thread_group Threads;For (char * * message = messages; *message; ++message) {Threads.create_thread (Boost::bind (Sync_echo, *message));boost::this_thread::sleep (boost::p osix_time::millisec);}Threads.join_all ();}core function Sync_echo. It contains all the logic to connect to the server, send the message, and then wait for the Echo to echo. you will find that when reading, I use the free function read (), because I want to read all the contents before ' \ n '. The Sock.read_some () method cannot meet this together oh IU, as it will only read available, not all of the messages. the third parameter of the read () method is the completion handle. When all messages are read, it returns 0. Otherwise, it will return the maximum buffer size I can get to the next (until the end of the read). In our case, the return result is always 1, because I never want to read more than we need. in Main (), we create several threads, each of which is responsible for sending the message to the client and then waiting for the operation to end. If you run this program, you will see the following output:server echoed our John says Hi:okserver echoed our so does James:okserver echoed our Lucy just got Home:okserver echoed our Boost.asio is fun!: OKNote that because we are synchronous, we do not need to call Service.run ().
TCP Synchronization Service sideIt is very easy to write the Echo synchronization service side, referring to the following code snippet:Io_service Service;size_t read_complete (char * buff, const Error_code & err, size_tbytes) {if (err) return 0;bool found = std::find (buff, buff + bytes, ' \ n ') < buff + bytes;// we read one by one until we read the carriage return, not the cache return found 0:1;}void Handle_connections () {ip::tcp::acceptor acceptor (service, Ip::tcp::endpoint (ip::tcp:: V4 (), 8001));Char buff[1024];While (true) {Ip::tcp::socket Sock (service);acceptor.accept (sock);int bytes = Read (sock, buffer (buff), page71image1824Boost::bind (read_complete,buff,_1,_2));std::string msg (buff, bytes);sock.write_some (Buffer (msg)); sock.close ();}}int main (int argc, char* argv[]) {handle_connections ();}the logic of the service side is mainly in handle_connections (). Because we are single-threaded, we accept a client request, read the message it sends to us, and then echo back, and then wait for the next connection. You can be sure that when two clients are connected at the same time, the second client does not wait for the service end to finish serving the first client. It is important to note that because we are synchronous, we do not need to call Service.run ().
TCP Asynchronous Clientwhen we start to async, the coding gets a little bit more complicated. We will build the connection class shown in the second chapter of the hold activity. observing the next code in this section, you will find that no asynchronous operation has initiated a new asynchronous operation to keep Service.run () working. first, the core functions are as follows:
#define MEM_FN (x)       boost::bind (&self_type::x, Shared_from_this ())   #define MEM_FN1 (x, y)    boost:: Bind (&self_type::x, shared_from_ this   (), y)   #define MEM_FN2 (x, Y, z)  boost::bind (&self_type: : x, Shared_from_ this   (), y,z)
   Class Talk_to_svr:public boost::enable_shared_from_this<talk_to_svr>                     , boost::noncopyable {
       typedef TALK_TO_SVR SELF_TYPE;       TALK_TO_SVR (const std::string & Message)
         : Sock_ (Service), Started_ (True), Message_ (message) {}       void Start (Ip::tcp::endpoint EP) {
           Sock_.async_connect (EP, MEM_FN1 (On_connect,_1));       }

Public

typedef boost::system::error_code Error_code;

       typedef boost::shared_ptr<talk_to_svr> PTR;       Static PTR Start (Ip::tcp::endpoint EP, const std::string &
   Message) {           ptr new_ (new TALK_TO_SVR (message));           New_->start (EP);           return new_;
       }       void Stop () {
           if (!started_) return;           Started_ = false;           Sock_.close ();
       }       bool Started () {return started_;}       ...
   Private:       ip::tcp::socket sock_;       enum {max_msg = 1024x768};       Char read_buffer_[max_msg];       Char write_buffer_[max_msg];       BOOL Started_;       Std::string Message_;

};

We always need to use a smart pointer to Talk_to_svr, so that when there is an asynchronous operation on an instance of Tack_to_svr, that instance is always active. To avoid errors, such as building an instance of a Talk_to_svr object on a stack, I set the constructor to private and do not allow copy construction (inherited from Boost::noncopyable).we have core methods, such as Start (), Stop (), and started (), and they do things just as their names say. If you need to establish a connection, call Talk_to_svr::start (endpoint, message). We also have a read buffer and a write buffer. (Read_buufer_ and Write_buffer_). mem_fn* is a handy macro that enforces the use of a smart pointer to *this through the Shared_ptr_from_this () method. the following lines of code are very different from the previous explanations:
Equivalent to "Sock_.async_connect (EP, MEM_FN1 (On_connect,_1));"   Sock_.async_connect (EP,
       Boost::bind (&talk_to_svr::on_connect,shared_ptr_from_this (), _1));   Sock_.async_connect (EP, Boost::bind (&talk_to_svr::on_connect,this,_1));
In the above example, we have correctly created the async_connect handle, and it retains a smart pointer to the Talk_to_server instance before the call finishes processing the handle, guaranteeing that when it occursTalk_to_server Instancesor keep it active. in the following example, we mistakenly created a handle to the completion handle, and when it is called, the Talk_to_server instance is probably already freed. when reading from or writing to the socket, you use the following code snippet:
void Do_read () {       async_read (sock_, buffer (read_buffer_),
                   MEM_FN2 (read_complete,_1,_2), mem_fn2 (on_read,_1,_2));
   }   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) {
       Similar to the TCP client   }
the Do_read () method guarantees that when On_read () is called, we read a row from the server. The Do_write () method copies the information to a buffer (given that MSG may have been freed when async_write occurs), and then ensures that the actual write occurs On_write () is called. then the most important method, this method contains the main logic of the class:
void On_connect (const Error_code & err) {       if (!err)      do_write (Message_ + "\ n");       else            stop ();
   }   void On_read (const Error_code & err, size_t bytes) {
       if (!err) {           std::string copy (Read_buffer_, bytes-1);           Std::cout << "Server echoed our" << message_ << ":"

Std::endl; }

Stop (); }

<< (copy = = Message_?) "OK": "FAIL") <<
   void On_write (const Error_code & err, size_t bytes) {       do_read ();

}

when we are connected, we send a message to the server, Do_write (). When the write operation ends, On_write () is called, and it Initializes a Do_read () method when the Do_read () is completed. On_read () is called; here, we simply check to see if the returned information is a service-side echo and then launch the service. We'll send three messages to the server to make it a little more interesting:
int main (int argc, char* argv[]) {       ip::tcp::endpoint EP (Ip::address::from_string ("127.0.0.1"),
   8001);       char* messages[] = {"John says hi", "so does James", "Lucy got
   Home ", 0};       for (char * * message = messages; *message; ++message) {
           Talk_to_svr::start (EP, *message);
           Boost::this_thread::sleep (boost::p osix_time::millisec);       }
       Service.run ();   }
The code above produces the following output:
Server echoed our John says Hi:ok   Server echoed we does James:ok   server echoed our Lucy just got Home:ok




Boost.asio C + + Network programming translator (15)

Related Article

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.