asio_chat.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /* ASIO chat server client example
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. Unless required by applicable law or agreed to in writing, this
  4. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. #include "protocol_examples_common.h"
  8. #include "esp_log.h"
  9. #include "esp_event.h"
  10. #include "nvs_flash.h"
  11. #include "server.hpp"
  12. #include "client.hpp"
  13. #include <thread>
  14. #include <pthread.h>
  15. using asio::ip::tcp;
  16. static const char *TAG = "asio-chat";
  17. // This variable is necessary for `python test` execution, it provides synchronisation between server/client(as server should be started before client)
  18. std::mutex server_ready;
  19. #ifdef CONFIG_EXAMPLE_CHAT_CLIENT
  20. static void get_string(char *line, size_t size)
  21. {
  22. int count = 0;
  23. while (count < size) {
  24. int c = fgetc(stdin);
  25. if (c == '\n') {
  26. line[count] = '\0';
  27. break;
  28. } else if (c > 0 && c < 127) {
  29. line[count] = c;
  30. ++count;
  31. }
  32. vTaskDelay(10 / portTICK_PERIOD_MS);
  33. }
  34. }
  35. void start_client(void)
  36. {
  37. const std::string port(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_PORT);
  38. const std::string name(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS);
  39. asio::io_context io_context;
  40. char line[128];
  41. tcp::resolver resolver(io_context);
  42. auto endpoints = resolver.resolve(name, port);
  43. chat_client c(io_context, endpoints);
  44. #ifdef CONFIG_EXAMPLE_CHAT_SERVER
  45. std::lock_guard<std::mutex> guard(server_ready);
  46. #endif
  47. std::thread t([&io_context]() { try {
  48. io_context.run();
  49. } catch (const std::exception &e) {
  50. ESP_LOGE(TAG, "Exception occured during client thread execution %s", e.what());
  51. }
  52. catch (...) {
  53. ESP_LOGE(TAG, "Unknown exception");
  54. }});
  55. do {
  56. ESP_LOGI(TAG, "CLIENT: Waiting for input");
  57. get_string(line, sizeof(line));
  58. chat_message msg;
  59. msg.body_length(std::strlen(line));
  60. std::memcpy(msg.body(), line, msg.body_length());
  61. msg.encode_header();
  62. c.write(msg);
  63. sleep(1);
  64. } while (strcmp(line, "exit") != 0);
  65. c.close();
  66. t.join();
  67. }
  68. #endif // CONFIG_EXAMPLE_CHAT_CLIENT
  69. extern "C" void app_main(void)
  70. {
  71. ESP_ERROR_CHECK(nvs_flash_init());
  72. esp_netif_init();
  73. ESP_ERROR_CHECK(esp_event_loop_create_default());
  74. /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
  75. * Read "Establishing Wi-Fi or Ethernet Connection" section in
  76. * examples/protocols/README.md for more information about this function.
  77. */
  78. ESP_ERROR_CHECK(example_connect());
  79. try {
  80. #ifdef CONFIG_EXAMPLE_CHAT_SERVER
  81. asio::io_context io_context;
  82. chat_server server(io_context, tcp::endpoint(tcp::v4(), std::atoi(CONFIG_EXAMPLE_CHAT_SERVER_BIND_PORT)));
  83. std::thread t = std::thread([&io_context]() { // Chat server starting here
  84. try {
  85. io_context.run();
  86. } catch (const std::exception &e) {
  87. ESP_LOGE(TAG, "Exception occured during server thread execution %s", e.what());
  88. }
  89. catch (...) {
  90. ESP_LOGE(TAG, "Unknown exception");
  91. }});;
  92. #endif
  93. #ifdef CONFIG_EXAMPLE_CHAT_CLIENT
  94. start_client();
  95. #endif
  96. #ifdef CONFIG_EXAMPLE_CHAT_SERVER
  97. t.join();
  98. #endif
  99. } catch (const std::exception &e) {
  100. ESP_LOGE(TAG, "Exception occured during run %s", e.what());
  101. } catch (...) {
  102. ESP_LOGE(TAG, "Unknown exception");
  103. }
  104. ESP_ERROR_CHECK(example_disconnect());
  105. }