• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // tcp_server.cpp
3 // ~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #include <boost/asio/io_context.hpp>
12 #include <boost/asio/ip/tcp.hpp>
13 #include <boost/asio/read.hpp>
14 #include <boost/asio/write.hpp>
15 #include <boost/shared_ptr.hpp>
16 #include <cstdio>
17 #include <cstdlib>
18 #include <cstring>
19 #include <vector>
20 
21 using boost::asio::ip::tcp;
22 
23 #include <boost/asio/yield.hpp>
24 
25 class tcp_server : boost::asio::coroutine
26 {
27 public:
tcp_server(tcp::acceptor & acceptor,std::size_t buf_size)28   tcp_server(tcp::acceptor& acceptor, std::size_t buf_size) :
29     acceptor_(acceptor),
30     socket_(acceptor_.get_executor()),
31     buffer_(buf_size)
32   {
33   }
34 
operator ()(boost::system::error_code ec,std::size_t n=0)35   void operator()(boost::system::error_code ec, std::size_t n = 0)
36   {
37     reenter (this) for (;;)
38     {
39       yield acceptor_.async_accept(socket_, ref(this));
40 
41       while (!ec)
42       {
43         yield boost::asio::async_read(socket_,
44             boost::asio::buffer(buffer_), ref(this));
45 
46         if (!ec)
47         {
48           for (std::size_t i = 0; i < n; ++i) buffer_[i] = ~buffer_[i];
49 
50           yield boost::asio::async_write(socket_,
51               boost::asio::buffer(buffer_), ref(this));
52         }
53       }
54 
55       socket_.close();
56     }
57   }
58 
59   struct ref
60   {
reftcp_server::ref61     explicit ref(tcp_server* p)
62       : p_(p)
63     {
64     }
65 
operator ()tcp_server::ref66     void operator()(boost::system::error_code ec, std::size_t n = 0)
67     {
68       (*p_)(ec, n);
69     }
70 
71   private:
72     tcp_server* p_;
73   };
74 
75 private:
76   tcp::acceptor& acceptor_;
77   tcp::socket socket_;
78   std::vector<unsigned char> buffer_;
79   tcp::endpoint sender_;
80 };
81 
82 #include <boost/asio/unyield.hpp>
83 
main(int argc,char * argv[])84 int main(int argc, char* argv[])
85 {
86   if (argc != 5)
87   {
88     std::fprintf(stderr,
89         "Usage: tcp_server <port> <nconns> "
90         "<bufsize> {spin|block}\n");
91     return 1;
92   }
93 
94   unsigned short port = static_cast<unsigned short>(std::atoi(argv[1]));
95   int max_connections = std::atoi(argv[2]);
96   std::size_t buf_size = std::atoi(argv[3]);
97   bool spin = (std::strcmp(argv[4], "spin") == 0);
98 
99   boost::asio::io_context io_context(1);
100   tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));
101   std::vector<boost::shared_ptr<tcp_server> > servers;
102 
103   for (int i = 0; i < max_connections; ++i)
104   {
105     boost::shared_ptr<tcp_server> s(new tcp_server(acceptor, buf_size));
106     servers.push_back(s);
107     (*s)(boost::system::error_code());
108   }
109 
110   if (spin)
111     for (;;) io_context.poll();
112   else
113     io_context.run();
114 }
115