Analysis of BOOST.ASIO Source Code (3) ---- Process Analysis

 One of the common process analysis (Tcp asynchronous connection)

 

We use a simple demo to analyze the process of Tcp asynchronous connection:

copy code

1 #include <iostream>
 2 #include <boost/asio.hpp>
 3
 4 // Asynchronous connection callback function
 5 void on_connect(boost::system::error_code ec)
 6 {
 7 if (ec) // connection failed, output error code
 8         std::cout << "async connect error:" << ec.message() << std::endl;
 9 else // Connection succeeded
10         std::cout << "async connect ok!" << std::endl;
11 }
12
13 int main()
14 {
15 boost::asio::io_service ios; // create io_service object
16     boost::asio::ip::tcp::endpoint addr(
17         boost::asio::ip::address::from_string("127.0.0.1"), 12345);  // server端地址
18 boost::asio::ip::tcp::socket conn_socket(ios); // Create a socket object of tcp protocol
19 conn_socket.async_connect(addr, &on_connect); // initiate an asynchronous connection request
20 ios.run(); // Call io_service::run, wait for the result of the asynchronous operation
21
22     std::cin.get();
23     return 0;
24 }

copy code

 


The sequence diagram of the asynchronous connection request in this code in the asio source code is as follows:

 

      Among them, basic_socket is a template class, and the definition of socket in tcp protocol is as follows:
            typedef basic_socket<tcp> socket;


      reactor的定义如下:
      #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
            typedef class null_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_IOCP)
            typedef class select_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_EPOLL)
            typedef class epoll_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_KQUEUE)
            typedef class kqueue_reactor reactor;
      #elif defined(BOOST_ASIO_HAS_DEV_POLL)
            typedef class dev_poll_reactor reactor;
      #else
            typedef class select_reactor reactor;
      #endif

      The most noteworthy point in this sequence diagram is that under the Windows platform, asynchronous connection requests are not handled by Iocp, but by the select model, which is the biggest difference from asynchronously reading and writing data.

 


* The second common process analysis (Tcp asynchronously accepts connections)

 

We use a simple demo to analyze the process of Tcp asynchronous connection:

copy code

1 #include <iostream>
 2 #include <boost/asio.hpp>
 3 #include <boost/bind.hpp>
 4
 5 // Asynchronous connection callback function
 6 void on_accept(boost::system::error_code ec, boost::asio::ip::tcp::socket * socket_ptr)
 7 {
 8 if (ec) // connection failed, output error code
 9         std::cout << "async accept error:" << ec.message() << std::endl;
10 else // connect successfully
11         std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl;
12
13 // Disconnect, release resources.
14     socket_ptr->close(), delete socket_ptr;
15 }
16
17 int main()
18 {
19 boost::asio::io_service ios; // Create io_service object
20     boost::asio::ip::tcp::endpoint addr(
21         boost::asio::ip::address::from_string("0.0.0.0"), 12345);  // server端地址
22 boost::asio::ip::tcp::acceptor acceptor(ios, addr, false); // create acceptor object
23     boost::asio::ip::tcp::socket * socket_ptr = new boost::asio::ip::tcp::socket(ios);
24     acceptor.async_accept(*socket_ptr
25 , boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr)); // call asynchronous accept request
26 ios.run(); // Call io_service::run, wait for the result of the asynchronous operation
27
28     std::cin.get();
29     return 0;
30 }

copy code

 

The sequence diagram of the asynchronous connection request in this code in the asio source code is as follows:

 


* The third common process analysis (Tcp asynchronous read and write data)

 

Based on the example in the previous section, we extend a simple demo to analyze the process of asynchronously reading and writing data through Tcp:

copy code

1 #include <iostream>
 2 #include <boost/asio.hpp>
 3 #include <boost/bind.hpp>
 4 #include <boost/shared_ptr.hpp>
 5 #include <boost/array.hpp>
 6
 7 typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
 8 typedef boost::array<char, 128> buffer_t;
 9 typedef boost::shared_ptr<buffer_t> buffer_ptr_t;
10
11 // Asynchronous read data callback function
12 void on_read(boost::system::error_code ec
13     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
14 {
15     if (ec)
16         std::cout << "async write error:" << ec.message() << std::endl;
17     else
18     {
19         std::cout << "async read size:" << len;
20         std::cout << " info:" << std::string((char*)buffer_ptr->begin(), len) << std::endl;
21
22         // auto release socket and buffer.
23     }
24 }
25
26 // Asynchronous write data callback function
27 void on_write(boost::system::error_code ec
28     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
29 {
30     if (ec)
31         std::cout << "async write error:" << ec.message() << std::endl;
32     else
33     {
34         std::cout << "async write size:" << len << std::endl;
35         socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
36             , boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
37                 , socket_ptr, buffer_ptr));
38     }
39 }
40
41 // Asynchronous connection callback function
42 void on_accept(boost::system::error_code ec, socket_ptr_t socket_ptr)
43 {
44 if (ec) // connection failed, output error code
45     {
46         std::cout << "async accept error:" << ec.message() << std::endl;
47     }
48 else // Connection succeeded
49     {
50         std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl;
51         buffer_ptr_t buffer_ptr(new buffer_t);
52         strcpy_s((char*)buffer_ptr->begin(), buffer_t::size(), "abcdefg");
53         socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin()))
54             , boost::bind(&on_write, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
55                 , socket_ptr, buffer_ptr));
56     }
57 }
58
59 int main()
60 {
61 boost::asio::io_service ios; // create io_service object
62     boost::asio::ip::tcp::endpoint addr(
63         boost::asio::ip::address::from_string("0.0.0.0"), 12345);  // server端地址
64 boost::asio::ip::tcp::acceptor acceptor(ios, addr, false); // create acceptor object
65     socket_ptr_t socket_ptr(new boost::asio::ip::tcp::socket(ios));
66     acceptor.async_accept(*socket_ptr
67 , boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr)); // call asynchronous accept request
68 ios.run(); // Call io_service::run, wait for the result of the asynchronous operation
69
70     std::cout << "press enter key...";
71     std::cin.get();
72     return 0;
73 }

copy code

 

The sequence diagram of the asynchronous connection request in this code in the asio source code is as follows:

 


* The fourth common process analysis (Tcp forced to close the connection)

Based on the example in the previous section, we extend a simple demo to analyze the process of forcibly closing the connection by Tcp:

copy code

1 #include <iostream>
 2 #include <boost/asio.hpp>
 3 #include <boost/bind.hpp>
 4 #include <boost/shared_ptr.hpp>
 5 #include <boost/array.hpp>
 6
 7 typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
 8 typedef boost::array<char, 128> buffer_t;
 9 typedef boost::shared_ptr<buffer_t> buffer_ptr_t;
10
11 // Asynchronous read data callback function
12 void on_read(boost::system::error_code ec
13     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
14 {
15 if (ec) // connection failed, output error code
16     {
17         std::cout << "async read error:" << ec.message() << std::endl;
18     }
19 }
20
21 // Asynchronous write data callback function
22 void on_write(boost::system::error_code ec
23     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
24 {
25 if (ec) // connection failed, output error code
26     {
27         std::cout << "async write error:" << ec.message() << std::endl;
28     }
29 }
30
31 // Asynchronous connection callback function
32 void on_accept(boost::system::error_code ec, socket_ptr_t socket_ptr)
33 {
34 if (ec) // connection failed, output error code
35     {
36         std::cout << "async accept error:" << ec.message() << std::endl;
37     }
38 else // Connection succeeded
39     {
40         std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl;
41
42         {
43             buffer_ptr_t buffer_ptr(new buffer_t);
44             strcpy_s((char*)buffer_ptr->begin(), buffer_t::size(), "abcdefg");
45             socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin()))
46                 , boost::bind(&on_write, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
47                 , socket_ptr, buffer_ptr));
48         }
49
50         {
51             buffer_ptr_t buffer_ptr(new buffer_t);
52             socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
53                 , boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
54                 , socket_ptr, buffer_ptr));
55         }
56
57 /// Force close the connection
58         socket_ptr->close(ec);
59         if (ec)
60             std::cout << "close error:" << ec.message() << std::endl;
61     }
62 }
63
64 int main()
65 {
66 boost::asio::io_service ios; // create io_service object
67     boost::asio::ip::tcp::endpoint addr(
68         boost::asio::ip::address::from_string("0.0.0.0"), 12345);  // server端地址
69 boost::asio::ip::tcp::acceptor acceptor(ios, addr, false); // create acceptor object
70     socket_ptr_t socket_ptr(new boost::asio::ip::tcp::socket(ios));
71     acceptor.async_accept(*socket_ptr
72 , boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr)); // call asynchronous accept request
73     socket_ptr.reset();
74 ios.run(); // Call io_service::run, wait for the result of the asynchronous operation
75
76     std::cout << "press enter key...";
77     std::cin.get();
78     return 0;
79 }

copy code

In this example, after receiving the connection from the client, an asynchronous read request and an asynchronous write request are initiated immediately, and then the socket is forcibly closed immediately.

Among them, the sequence diagram of the request to forcibly close the socket in the asio source code is as follows:

 

* Common process analysis five (Tcp closes the connection gracefully)

We are still based on the example in Section 3, and extend a simple demo to analyze the process of Tcp closing the connection gracefully:

copy code

1 #include <iostream>
 2 #include <boost/asio.hpp>
 3 #include <boost/bind.hpp>
 4 #include <boost/shared_ptr.hpp>
 5 #include <boost/array.hpp>
 6
 7 typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr_t;
 8 typedef boost::array<char, 32> buffer_t;
 9 typedef boost::shared_ptr<buffer_t> buffer_ptr_t;
10
11
12 // Asynchronous read data callback function
13 void on_read(boost::system::error_code ec
14     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
15 {
16     static int si = 0;
17 if (ec) // connection failed, output error code
18     {
19         std::cout << "async read(" << si++ << ") error:" << ec.message() << std::endl;
20         socket_ptr->shutdown(boost::asio::socket_base::shutdown_receive, ec);
21         socket_ptr->close(ec);
22         if (ec)
23             std::cout << "close error:" << ec.message() << std::endl;
24     }
25     else
26     {
27         std::cout << "read(" << si++ << ") len:" << len << std::endl;
28
29         socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
30             , boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
31             , socket_ptr, buffer_ptr));
32     }
33 }
34
35 // Asynchronous write data callback function
36 void on_write(boost::system::error_code ec
37     , std::size_t len, socket_ptr_t socket_ptr, buffer_ptr_t buffer_ptr)
38 {
39 if (ec) // connection failed, output error code
40     {
41         std::cout << "async write error:" << ec.message() << std::endl;
42     }
43     else
44     {
45 /// Close the connection gracefully
46         socket_ptr->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
47         if (ec)
48             std::cout << "shutdown send error:" << ec.message() << std::endl;
49     }
50 }
51
52 // Asynchronous connection callback function
53 void on_accept(boost::system::error_code ec, socket_ptr_t socket_ptr)
54 {
55 if (ec) // connection failed, output error code
56     {
57         std::cout << "async accept error:" << ec.message() << std::endl;
58     }
59 else // Connection succeeded
60     {
61         std::cout << "async accept from (" << socket_ptr->remote_endpoint() << ")" << std::endl;
62
63         {
64             buffer_ptr_t buffer_ptr(new buffer_t);
65             socket_ptr->async_read_some(boost::asio::buffer(buffer_ptr.get(), buffer_t::size())
66                 , boost::bind(&on_read, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
67                 , socket_ptr, buffer_ptr));
68         }
69
70         {
71             buffer_ptr_t buffer_ptr(new buffer_t);
72             strcpy_s((char*)buffer_ptr->begin(), buffer_t::size(), "abcdefg");
73             socket_ptr->async_write_some(boost::asio::buffer(buffer_ptr.get(), strlen((char*)buffer_ptr->begin()))
74                 , boost::bind(&on_write, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred
75                 , socket_ptr, buffer_ptr));
76         }
77     }
78 }
79
80 int main()
81 {
82 boost::asio::io_service ios; // create io_service object
83     boost::asio::ip::tcp::endpoint addr(
84         boost::asio::ip::address::from_string("0.0.0.0"), 12345);  // server端地址
85 boost::asio::ip::tcp::acceptor acceptor(ios, addr, false); // create acceptor object
86     socket_ptr_t socket_ptr(new boost::asio::ip::tcp::socket(ios));
87     acceptor.async_accept(*socket_ptr
88 , boost::bind(&on_accept, boost::asio::placeholders::error, socket_ptr)); // call asynchronous accept request
89     socket_ptr.reset();
90 ios.run(); // Call io_service::run, wait for the result of the asynchronous operation
91
92     std::cout << "press enter key...";
93     std::cin.get();
94     return 0;
95 }

copy code

 

      In this example, after receiving the connection from the client and sending data to the client, first close the sending channel of the socket, and then wait for all the data in the receiving buffer of the socket to be read, and then close the receiving channel of the socket. At this time, the receiving and sending channels of the socket are closed, and no process can use this socket to send and receive data, but the system resources occupied by it have not been released, and the data in the underlying send buffer is not guaranteed to be fully sent. After this, a close operation is performed in order to release system resources.
      If you want the data in the underlying send buffer to still be sent before releasing the system resources, you need to set a waiting time in the linger attribute of the socket to have time to wait for the data in the send buffer to be sent. But the value in linger is definitely not the bigger the better, because the principle is that the operating system helps to reserve the resources of the socket to wait for the data in the send buffer to be sent. The socket keeps waiting, which is a great waste of system resources. Therefore, on the server side that needs to handle a large number of connections, the value of linger must not be too large.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325448506&siteId=291194637