boost asio one client one thread

  总结了一个简单的boost asio的tcp服务器端与客户端通信流程.模型是一个client对应一个线程。先做一个记录,后续再对此进行优化。

  环境:VS2017  + Boost 1.67

  server:

  1 #include <stdio.h> 
  2 #include <cstdlib> 
  3 #include <iostream> 
  4 #include <boost/thread.hpp> 
  5 #include <boost/aligned_storage.hpp> 
  6 #include <boost/array.hpp> 
  7 #include <boost/bind.hpp> 
  8 #include <boost/enable_shared_from_this.hpp> 
  9 #include <boost/noncopyable.hpp> 
 10 #include <boost/shared_ptr.hpp> 
 11 #include <boost/asio.hpp> 
 12 
 13 using boost::asio::ip::tcp;
 14 
 15 class handler_allocator
 16     : private boost::noncopyable
 17 {
 18 public:
 19     handler_allocator()
 20         : in_use_(false)
 21     {
 22     }
 23 
 24     void* allocate(std::size_t size)
 25     {
 26         if (!in_use_ && size < storage_.size)
 27         {
 28             in_use_ = true;
 29             return storage_.address();
 30         }
 31         else
 32         {
 33             return ::operator new(size);
 34         }
 35     }
 36 
 37     void deallocate(void* pointer)
 38     {
 39         if (pointer == storage_.address())
 40         {
 41             in_use_ = false;
 42         }
 43         else
 44         {
 45             ::operator delete(pointer);
 46         }
 47     }
 48 
 49 private:
 50     // Storage space used for handler-based custom memory allocation. 
 51     boost::aligned_storage<1024> storage_;
 52 
 53     // Whether the handler-based custom allocation storage has been used. 
 54     bool in_use_;
 55 };
 56 
 57 template <typename Handler>
 58 class custom_alloc_handler
 59 {
 60 public:
 61     custom_alloc_handler(handler_allocator& a, Handler h)
 62         : allocator_(a),
 63         handler_(h)
 64     {
 65     }
 66 
 67     template <typename Arg1>
 68     void operator()(Arg1 arg1)
 69     {
 70         handler_(arg1);
 71     }
 72 
 73     template <typename Arg1, typename Arg2>
 74     void operator()(Arg1 arg1, Arg2 arg2)
 75     {
 76         handler_(arg1, arg2);
 77     }
 78 
 79     friend void* asio_handler_allocate(std::size_t size,
 80         custom_alloc_handler<Handler>* this_handler)
 81     {
 82         return this_handler->allocator_.allocate(size);
 83     }
 84 
 85     friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
 86         custom_alloc_handler<Handler>* this_handler)
 87     {
 88         this_handler->allocator_.deallocate(pointer);
 89     }
 90 
 91 private:
 92     handler_allocator & allocator_;
 93     Handler handler_;
 94 };
 95 
 96 // Helper function to wrap a handler object to add custom allocation. 
 97 template <typename Handler>
 98 inline custom_alloc_handler<Handler> make_custom_alloc_handler(
 99     handler_allocator& a, Handler h)
100 {
101     return custom_alloc_handler<Handler>(a, h);
102 }
103 
104 /// A pool of io_service objects. 
105 class io_service_pool
106     : private boost::noncopyable
107 {
108 public:
109     /// Construct the io_service pool. 
110     explicit io_service_pool(std::size_t pool_size) : next_io_service_(0)
111     {
112         if (pool_size == 0)
113             throw std::runtime_error("io_service_pool size is 0");
114 
115         // Give all the io_services work to do so that their run() functions will not 
116         // exit until they are explicitly stopped. 
117         for (std::size_t i = 0; i < pool_size; ++i)
118         {
119             io_service_ptr io_service(new boost::asio::io_service);
120             work_ptr work(new boost::asio::io_service::work(*io_service));
121             io_services_.push_back(io_service);
122             work_.push_back(work);
123         }
124     }
125 
126     // Run all io_service objects in the pool. 
127     void run()
128     {
129         // Create a pool of threads to run all of the io_services. 
130         std::vector<boost::shared_ptr<boost::thread> > threads;
131         for (std::size_t i = 0; i < io_services_.size(); ++i)
132         {
133             boost::shared_ptr<boost::thread> thread(new boost::thread(
134                 boost::bind(&boost::asio::io_service::run, io_services_[i])));
135             threads.push_back(thread);
136         }
137 
138         // Wait for all threads in the pool to exit. 
139         for (std::size_t i = 0; i < threads.size(); ++i)
140             threads[i]->join();
141     }
142 
143     // Stop all io_service objects in the pool. 
144     void stop()
145     {
146         // Explicitly stop all io_services. 
147         for (std::size_t i = 0; i < io_services_.size(); ++i)
148             io_services_[i]->stop();
149     }
150 
151     // Get an io_service to use. 
152     boost::asio::io_service& get_io_service()
153     {
154         // Use a round-robin scheme to choose the next io_service to use. 
155         boost::asio::io_service& io_service = *io_services_[next_io_service_];
156         ++next_io_service_;
157         if (next_io_service_ == io_services_.size())
158             next_io_service_ = 0;
159         return io_service;
160     }
161 
162 private:
163     typedef boost::shared_ptr<boost::asio::io_service> io_service_ptr;
164     typedef boost::shared_ptr<boost::asio::io_service::work> work_ptr;
165 
166     /// The pool of io_services. 
167     std::vector<io_service_ptr> io_services_;
168 
169     /// The work that keeps the io_services running. 
170     std::vector<work_ptr> work_;
171 
172     /// The next io_service to use for a connection. 
173     std::size_t next_io_service_;
174 };
175 
176 class session
177     : public boost::enable_shared_from_this<session>
178 {
179 public:
180     session(boost::asio::io_service& work_service
181         , boost::asio::io_service& io_service)
182         : socket_(io_service)
183         , io_work_service(work_service)
184     {
185     }
186 
187     tcp::socket& socket()
188     {
189         return socket_;
190     }
191 
192     void start()
193     {
194 
195         boost::system::error_code error;
196         handle_write(error);
197 
198         socket_.async_read_some(boost::asio::buffer(data_),
199             make_custom_alloc_handler(allocator_,
200                 boost::bind(&session::handle_read,
201                     shared_from_this(),
202                     boost::asio::placeholders::error,
203                     boost::asio::placeholders::bytes_transferred)));
204     }
205 
206     void handle_read(const boost::system::error_code& error,
207         size_t bytes_transferred)
208     {
209         if (!error)
210         {
211             boost::shared_ptr<std::vector<char> > buf(new std::vector<char>);
212 
213             buf->resize(bytes_transferred);
214             std::copy(data_.begin(), data_.begin() + bytes_transferred, buf->begin());
215             io_work_service.post(boost::bind(&session::on_receive
216                 , shared_from_this(), buf, bytes_transferred));
217 
218             socket_.async_read_some(boost::asio::buffer(data_),
219                 make_custom_alloc_handler(allocator_,
220                     boost::bind(&session::handle_read,
221                         shared_from_this(),
222                         boost::asio::placeholders::error,
223                         boost::asio::placeholders::bytes_transferred)));
224         }
225     }
226 
227     void handle_write(const boost::system::error_code& error)
228     {
229         if (!error)
230         {
231             char notice[] = "Welcome to Connect to Hiper Service";
232             size_t num;
233             try
234             {
235                 num = socket_.send(boost::asio::buffer(notice));
236             }
237             catch (std::exception &e)
238             {
239                 std::cout << "exception: " << e.what() << std::endl;
240             }
241             if (num>0)
242             {
243                 std::cout << "send : " << notice << std::endl;
244             }
245         }
246     }
247 
248     void on_receive(boost::shared_ptr<std::vector<char> > buffers
249         , size_t bytes_transferred)
250     {
251         char* data_stream = &(*buffers->begin());
252         // in here finish the work. 
253         std::cout << "receive :" << bytes_transferred << " bytes." <<
254             "message :" << data_stream << std::endl;
255 
256         boost::system::error_code error;
257         handle_write(error);
258     }
259 
260 private:
261     // The io_service used to finish the work. 
262     boost::asio::io_service& io_work_service;
263 
264     // The socket used to communicate with the client. 
265     tcp::socket socket_;
266 
267     // Buffer used to store data received from the client. 
268     boost::array<char, 1024> data_;
269 
270     // The allocator to use for handler-based custom memory allocation. 
271     handler_allocator allocator_;
272 };
273 
274 typedef boost::shared_ptr<session> session_ptr;
275 
276 class server
277 {
278 public:
279     server(short port, std::size_t io_service_pool_size)
280         : io_service_pool_(io_service_pool_size)
281         , io_service_work_pool_(io_service_pool_size)
282         , acceptor_(io_service_pool_.get_io_service(), tcp::endpoint(tcp::v4(), port))
283     {
284         session_ptr new_session(new session(io_service_work_pool_.get_io_service()
285             , io_service_pool_.get_io_service()));
286         acceptor_.async_accept(new_session->socket(),
287             boost::bind(&server::handle_accept, this, new_session,
288                 boost::asio::placeholders::error));
289     }
290 
291     void handle_accept(session_ptr new_session,
292         const boost::system::error_code& error)
293     {
294         if (!error)
295         {
296             new_session->start();
297             new_session.reset(new session(io_service_work_pool_.get_io_service()
298                 , io_service_pool_.get_io_service()));
299             acceptor_.async_accept(new_session->socket(),
300                 boost::bind(&server::handle_accept, this, new_session,
301                     boost::asio::placeholders::error));
302         }
303     }
304 
305     void run()
306     {
307         io_thread_.reset(new boost::thread(boost::bind(&io_service_pool::run
308             , &io_service_pool_)));
309         work_thread_.reset(new boost::thread(boost::bind(&io_service_pool::run
310             , &io_service_work_pool_)));
311     }
312 
313     void stop()
314     {
315         io_service_pool_.stop();
316         io_service_work_pool_.stop();
317 
318         io_thread_->join();
319         work_thread_->join();
320     }
321 
322 private:
323     boost::shared_ptr<boost::thread> io_thread_;
324     boost::shared_ptr<boost::thread> work_thread_;
325     io_service_pool io_service_pool_;
326     io_service_pool io_service_work_pool_;
327     tcp::acceptor acceptor_;
328 };
329 
330 
331 int main() {
332     server svr(8000, 10);
333     svr.run();
334 
335     while (true)
336     {
337         boost::this_thread::sleep(boost::posix_time::seconds(5));
338     }
339 
340 
341     return 0;
342 }

 

client:

  1 #include <iostream>
  2 #include <boost/shared_ptr.hpp>
  3 #include <boost/asio.hpp>
  4 #include <boost/asio/placeholders.hpp>
  5 #include <boost/system/error_code.hpp>
  6 #include <boost/bind/bind.hpp>
  7 #include<boost/thread.hpp>
  8 
  9 using namespace boost::asio;
 10 using namespace std;
 11 
 12 class client
 13 {
 14     typedef client this_type;
 15     typedef ip::tcp::acceptor acceptor_type;
 16     typedef ip::tcp::endpoint endpoint_type;
 17     typedef ip::tcp::socket socket_type;
 18     typedef ip::address address_type;
 19     typedef boost::shared_ptr<socket_type> sock_ptr;
 20     typedef vector<char> buffer_type;
 21 
 22 private:
 23     io_service m_io;
 24     buffer_type m_buf;
 25     endpoint_type m_ep;
 26 public:
 27     client() : m_buf(1024, 0), m_ep(address_type::from_string("127.0.0.1"), 8000)
 28     {
 29         start();
 30     }
 31 
 32     void run()
 33     {
 34         m_io.run();
 35     }
 36 
 37     void start()
 38     {
 39         sock_ptr sock(new socket_type(m_io));
 40         sock->async_connect(m_ep, boost::bind(&this_type::conn_handler, this, boost::asio::placeholders::error, sock));
 41     }
 42 
 43     void conn_handler(const boost::system::error_code&ec, sock_ptr sock)
 44     {
 45         if (ec)
 46         {
 47             std::cout << ec.message() << std::endl;
 48             return;
 49         }
 50         cout << "Receive from " << sock->remote_endpoint().address() << ": ";
 51         cout << "Port:" << sock->remote_endpoint().port() << endl;
 52         sock->async_read_some(buffer(m_buf), boost::bind(&client::read_handler, this, boost::asio::placeholders::error, sock));
 53     }
 54 
 55     void read_handler(const boost::system::error_code&ec, sock_ptr sock)
 56     {
 57         if (ec)
 58         {
 59             return;
 60         }
 61         sock->async_read_some(buffer(m_buf), boost::bind(&client::read_handler, this, boost::asio::placeholders::error, sock));
 62         cout << &m_buf[0] << endl;
 63 
 64 
 65         boost::this_thread::sleep(boost::posix_time::milliseconds(200));
 66 
 67         char pmsg[] = "client 6666";
 68 
 69         sock->async_write_some(buffer(pmsg), boost::bind(&this_type::write_handler, this, boost::asio::placeholders::error));
 70     }
 71 
 72     void write_handler(const boost::system::error_code& ec)
 73     {
 74         if (ec)
 75         {
 76             std::cout << ec.message() << std::endl;
 77             return;
 78         }
 79 
 80         std::cout << "send success!" << std::endl;
 81         
 82     }
 83 };
 84 
 85 int main()
 86 {
 87     try
 88     {
 89         cout << "Client start." << endl;
 90         client cl;
 91         cl.run();
 92     }
 93     catch (std::exception &e)
 94     {
 95         cout << e.what() << endl;
 96     }
 97 
 98     while (true)
 99     {
100         boost::this_thread::sleep(boost::posix_time::seconds(5));
101     }
102 
103     return 0;
104 }

   

 

posted @ 2018-08-06 19:56  HBright  阅读(546)  评论(0编辑  收藏  举报