UdpClientImpl.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #include "UdpClientImpl.h"
  2. #include <Logging.h>
  3. namespace Network {
  4. UdpClientImpl::UdpClientImpl(const std::string& listenAddress, const std::string& targetAddress, int targetPort, std::function<void(const std::string&)> callback) :
  5. m_bufferLength(1024),
  6. m_deadline(m_ioServiceAnswer),
  7. m_listenAddress(asio::ip::address::from_string(listenAddress)),
  8. m_targetAddress(asio::ip::address::from_string(targetAddress)),
  9. m_targetPort(targetPort),
  10. m_receiveSocket(m_ioService),
  11. m_answerSocket(m_ioServiceAnswer),
  12. m_targetEndpoint(m_targetAddress, m_targetPort),
  13. m_callback(callback)
  14. {
  15. m_thread = std::thread([&] { m_ioService.run(); });
  16. #ifdef __linux__
  17. pthread_setname_np(m_thread.native_handle(), "UdpClientImpl");
  18. #endif
  19. m_socketReceiveData.reserve(m_bufferLength);
  20. m_socketAnswerData.reserve(m_bufferLength);
  21. asio::ip::udp::endpoint listenEndpoint(m_targetAddress, m_targetPort);
  22. m_receiveSocket.open(listenEndpoint.protocol());
  23. m_receiveSocket.set_option(asio::ip::udp::socket::reuse_address(true));
  24. m_receiveSocket.bind(listenEndpoint);
  25. }
  26. UdpClientImpl::~UdpClientImpl()
  27. {
  28. m_ioService.stop();
  29. m_thread.join();
  30. }
  31. void UdpClientImpl::Receive()
  32. {
  33. ReceiveSocket();
  34. m_deadline.expires_at(asio::system_timer::time_point(std::chrono::system_clock::duration::max()));
  35. CheckDeadline();
  36. }
  37. std::string UdpClientImpl::Send(const std::string& data, int sourcePort)
  38. {
  39. asio::ip::udp::socket sendSocket(m_ioService);
  40. sendSocket.open(asio::ip::udp::v4());
  41. sendSocket.set_option(asio::ip::udp::socket::reuse_address(true));
  42. if (sourcePort != 0)
  43. {
  44. asio::ip::udp::endpoint sendEndpoint(m_listenAddress, sourcePort);
  45. sendSocket.bind(sendEndpoint);
  46. }
  47. try
  48. {
  49. sendSocket.connect(m_targetEndpoint);
  50. asio::ip::udp::endpoint listenEndpoint(m_listenAddress, sendSocket.local_endpoint().port());
  51. m_answerSocket.open(listenEndpoint.protocol());
  52. m_answerSocket.set_option(asio::ip::udp::socket::reuse_address(true));
  53. m_answerSocket.bind(listenEndpoint);
  54. sendSocket.send(asio::buffer(data));
  55. asio::error_code error = asio::error::would_block;
  56. std::size_t length = 0;
  57. m_deadline.expires_from_now(std::chrono::seconds(1));
  58. m_answerSocket.async_receive(asio::buffer(m_socketAnswerData.data(), m_bufferLength), std::bind(&UdpClientImpl::HandleAnswer, this, std::placeholders::_1, std::placeholders::_2, &error, &length));
  59. do m_ioServiceAnswer.run_one();
  60. while (error == asio::error::would_block);
  61. std::string answer;
  62. if (error != asio::error::operation_aborted)
  63. answer = std::string(m_socketAnswerData.begin(), m_socketAnswerData.begin() + length);
  64. else
  65. answer = "Error";
  66. m_answerSocket.close();
  67. return answer;
  68. }
  69. catch (const asio::system_error& ex)
  70. {
  71. std::stringstream ss;
  72. ss << "UdpClientImpl::Send() - Error: " << ex.what() << std::endl;
  73. Logging::Log(Logging::Severity::Error, ss.str());
  74. return "Error";
  75. }
  76. }
  77. void UdpClientImpl::Broadcast(const std::string& data, int sourcePort)
  78. {
  79. asio::ip::udp::socket sendSocket(m_ioService);
  80. sendSocket.open(asio::ip::udp::v4());
  81. sendSocket.set_option(asio::ip::udp::socket::reuse_address(true));
  82. sendSocket.set_option(asio::socket_base::broadcast(true));
  83. if (sourcePort != 0)
  84. {
  85. asio::ip::udp::endpoint sendEndpoint(m_listenAddress, sourcePort);
  86. sendSocket.bind(sendEndpoint);
  87. }
  88. asio::ip::udp::endpoint targetEndpoint(asio::ip::address_v4::broadcast(), m_targetPort);
  89. try
  90. {
  91. sendSocket.connect(targetEndpoint);
  92. sendSocket.send(asio::buffer(data));
  93. }
  94. catch (const asio::system_error& ex)
  95. {
  96. std::stringstream ss;
  97. ss << "UdpClientImpl::Broadcast() - Error: " << ex.what() << std::endl;
  98. Logging::Log(Logging::Severity::Error, ss.str());
  99. }
  100. sendSocket.close();
  101. }
  102. void UdpClientImpl::EnableMulticast()
  103. {
  104. m_receiveSocket.set_option(asio::ip::multicast::join_group(m_targetAddress.to_v4(), m_listenAddress.to_v4()));
  105. }
  106. void UdpClientImpl::CheckDeadline()
  107. {
  108. if (m_deadline.expires_at() <= std::chrono::system_clock::now())
  109. {
  110. m_answerSocket.close();
  111. m_deadline.expires_at(asio::system_timer::time_point(std::chrono::system_clock::duration::max()));
  112. }
  113. m_deadline.async_wait(std::bind(&UdpClientImpl::CheckDeadline, this));
  114. }
  115. void UdpClientImpl::HandleAnswer(const asio::error_code& error, std::size_t length, asio::error_code* out_error, std::size_t* out_length) const
  116. {
  117. *out_error = error;
  118. *out_length = length;
  119. }
  120. void UdpClientImpl::ReceiveSocket()
  121. {
  122. m_receiveSocket.async_receive_from(asio::buffer(m_socketReceiveData.data(), m_bufferLength), m_sourceEndpoint, std::bind(&UdpClientImpl::HandleReceiveSocket, this, std::placeholders::_1, std::placeholders::_2));
  123. }
  124. void UdpClientImpl::HandleReceiveSocket(const asio::error_code& error, size_t bytes)
  125. {
  126. if (error)
  127. return;
  128. if (m_callback)
  129. {
  130. std::vector<char>::iterator begin = m_socketReceiveData.begin();
  131. m_callback(std::string(begin, begin + bytes));
  132. }
  133. ReceiveSocket();
  134. }
  135. } // namespace Network