udp_server.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. //
  2. // udp_server.cpp
  3. // ~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 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. #include <boost/asio/io_context.hpp>
  11. #include <boost/asio/ip/udp.hpp>
  12. #include <boost/shared_ptr.hpp>
  13. #include <cstdio>
  14. #include <cstdlib>
  15. #include <cstring>
  16. #include <vector>
  17. #include "allocator.hpp"
  18. using boost::asio::ip::udp;
  19. #include <boost/asio/yield.hpp>
  20. class udp_server : boost::asio::coroutine
  21. {
  22. public:
  23. udp_server(boost::asio::io_context& io_context,
  24. unsigned short port, std::size_t buf_size) :
  25. socket_(io_context, udp::endpoint(udp::v4(), port)),
  26. buffer_(buf_size)
  27. {
  28. }
  29. void operator()(boost::system::error_code ec, std::size_t n = 0)
  30. {
  31. reenter (this) for (;;)
  32. {
  33. yield socket_.async_receive_from(
  34. boost::asio::buffer(buffer_),
  35. sender_, ref(this));
  36. if (!ec)
  37. {
  38. for (std::size_t i = 0; i < n; ++i) buffer_[i] = ~buffer_[i];
  39. socket_.send_to(boost::asio::buffer(buffer_, n), sender_, 0, ec);
  40. }
  41. }
  42. }
  43. friend void* asio_handler_allocate(std::size_t n, udp_server* s)
  44. {
  45. return s->allocator_.allocate(n);
  46. }
  47. friend void asio_handler_deallocate(void* p, std::size_t, udp_server* s)
  48. {
  49. s->allocator_.deallocate(p);
  50. }
  51. struct ref
  52. {
  53. explicit ref(udp_server* p)
  54. : p_(p)
  55. {
  56. }
  57. void operator()(boost::system::error_code ec, std::size_t n = 0)
  58. {
  59. (*p_)(ec, n);
  60. }
  61. private:
  62. udp_server* p_;
  63. friend void* asio_handler_allocate(std::size_t n, ref* r)
  64. {
  65. return asio_handler_allocate(n, r->p_);
  66. }
  67. friend void asio_handler_deallocate(void* p, std::size_t n, ref* r)
  68. {
  69. asio_handler_deallocate(p, n, r->p_);
  70. }
  71. };
  72. private:
  73. udp::socket socket_;
  74. std::vector<unsigned char> buffer_;
  75. udp::endpoint sender_;
  76. allocator allocator_;
  77. };
  78. #include <boost/asio/unyield.hpp>
  79. int main(int argc, char* argv[])
  80. {
  81. if (argc != 5)
  82. {
  83. std::fprintf(stderr,
  84. "Usage: udp_server <port1> <nports> "
  85. "<bufsize> {spin|block}\n");
  86. return 1;
  87. }
  88. unsigned short first_port = static_cast<unsigned short>(std::atoi(argv[1]));
  89. unsigned short num_ports = static_cast<unsigned short>(std::atoi(argv[2]));
  90. std::size_t buf_size = std::atoi(argv[3]);
  91. bool spin = (std::strcmp(argv[4], "spin") == 0);
  92. boost::asio::io_context io_context(1);
  93. std::vector<boost::shared_ptr<udp_server> > servers;
  94. for (unsigned short i = 0; i < num_ports; ++i)
  95. {
  96. unsigned short port = first_port + i;
  97. boost::shared_ptr<udp_server> s(new udp_server(io_context, port, buf_size));
  98. servers.push_back(s);
  99. (*s)(boost::system::error_code());
  100. }
  101. if (spin)
  102. for (;;) io_context.poll();
  103. else
  104. io_context.run();
  105. }