websocket_client_coro.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. //------------------------------------------------------------------------------
  10. //
  11. // Example: WebSocket client, coroutine
  12. //
  13. //------------------------------------------------------------------------------
  14. #include <boost/beast/core.hpp>
  15. #include <boost/beast/websocket.hpp>
  16. #include <boost/asio/spawn.hpp>
  17. #include <cstdlib>
  18. #include <functional>
  19. #include <iostream>
  20. #include <string>
  21. namespace beast = boost::beast; // from <boost/beast.hpp>
  22. namespace http = beast::http; // from <boost/beast/http.hpp>
  23. namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
  24. namespace net = boost::asio; // from <boost/asio.hpp>
  25. using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
  26. //------------------------------------------------------------------------------
  27. // Report a failure
  28. void
  29. fail(beast::error_code ec, char const* what)
  30. {
  31. std::cerr << what << ": " << ec.message() << "\n";
  32. }
  33. // Sends a WebSocket message and prints the response
  34. void
  35. do_session(
  36. std::string const& host,
  37. std::string const& port,
  38. std::string const& text,
  39. net::io_context& ioc,
  40. net::yield_context yield)
  41. {
  42. beast::error_code ec;
  43. // These objects perform our I/O
  44. tcp::resolver resolver(ioc);
  45. websocket::stream<beast::tcp_stream> ws(ioc);
  46. // Look up the domain name
  47. auto const results = resolver.async_resolve(host, port, yield[ec]);
  48. if(ec)
  49. return fail(ec, "resolve");
  50. // Set a timeout on the operation
  51. beast::get_lowest_layer(ws).expires_after(std::chrono::seconds(30));
  52. // Make the connection on the IP address we get from a lookup
  53. beast::get_lowest_layer(ws).async_connect(results, yield[ec]);
  54. if(ec)
  55. return fail(ec, "connect");
  56. // Turn off the timeout on the tcp_stream, because
  57. // the websocket stream has its own timeout system.
  58. beast::get_lowest_layer(ws).expires_never();
  59. // Set suggested timeout settings for the websocket
  60. ws.set_option(
  61. websocket::stream_base::timeout::suggested(
  62. beast::role_type::client));
  63. // Set a decorator to change the User-Agent of the handshake
  64. ws.set_option(websocket::stream_base::decorator(
  65. [](websocket::request_type& req)
  66. {
  67. req.set(http::field::user_agent,
  68. std::string(BOOST_BEAST_VERSION_STRING) +
  69. " websocket-client-coro");
  70. }));
  71. // Perform the websocket handshake
  72. ws.async_handshake(host, "/", yield[ec]);
  73. if(ec)
  74. return fail(ec, "handshake");
  75. // Send the message
  76. ws.async_write(net::buffer(std::string(text)), yield[ec]);
  77. if(ec)
  78. return fail(ec, "write");
  79. // This buffer will hold the incoming message
  80. beast::flat_buffer buffer;
  81. // Read a message into our buffer
  82. ws.async_read(buffer, yield[ec]);
  83. if(ec)
  84. return fail(ec, "read");
  85. // Close the WebSocket connection
  86. ws.async_close(websocket::close_code::normal, yield[ec]);
  87. if(ec)
  88. return fail(ec, "close");
  89. // If we get here then the connection is closed gracefully
  90. // The make_printable() function helps print a ConstBufferSequence
  91. std::cout << beast::make_printable(buffer.data()) << std::endl;
  92. }
  93. //------------------------------------------------------------------------------
  94. int main(int argc, char** argv)
  95. {
  96. // Check command line arguments.
  97. if(argc != 4)
  98. {
  99. std::cerr <<
  100. "Usage: websocket-client-coro <host> <port> <text>\n" <<
  101. "Example:\n" <<
  102. " websocket-client-coro echo.websocket.org 80 \"Hello, world!\"\n";
  103. return EXIT_FAILURE;
  104. }
  105. auto const host = argv[1];
  106. auto const port = argv[2];
  107. auto const text = argv[3];
  108. // The io_context is required for all I/O
  109. net::io_context ioc;
  110. // Launch the asynchronous operation
  111. boost::asio::spawn(ioc, std::bind(
  112. &do_session,
  113. std::string(host),
  114. std::string(port),
  115. std::string(text),
  116. std::ref(ioc),
  117. std::placeholders::_1));
  118. // Run the I/O service. The call will return when
  119. // the socket is closed.
  120. ioc.run();
  121. return EXIT_SUCCESS;
  122. }