From 4e98ec01fc2f66573d841e05c80c675db8dc386b Mon Sep 17 00:00:00 2001 From: Thurman Gillespy Date: Tue, 23 Apr 2019 23:08:31 -0700 Subject: [PATCH 1/6] stubbed echo_server --- example/echo_binary_text_server_demo.cpp | 104 +++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 example/echo_binary_text_server_demo.cpp diff --git a/example/echo_binary_text_server_demo.cpp b/example/echo_binary_text_server_demo.cpp new file mode 100644 index 00000000..1d546a7a --- /dev/null +++ b/example/echo_binary_text_server_demo.cpp @@ -0,0 +1,104 @@ +/** + * @file + * + * @ingroup example_module + * + * @brief TCP acceptor (server) that receives binary text messages, converts + * to upper case, then echos back to TCP connector (client). + * + * @author Thurman Gillespy + * + * Copyright (c) Thurman Gillespy + * 4/23/19 + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + * Sample make file: +g++ -std=c++17 -Wall -Werror \ +-I ../include \ +-I ~/Projects/utility-rack/include/ \ +-I ~/Projects/asio/asio/include/ \ +-I ~/Projects/boost_1_69_0/ \ +echo_binary_text_server_demo.cpp -lpthread -o echo_server + * + */ + +#include +#include // EXIT_SUCCESS +#include // std::size_t +#include +#include +#include + +#include "net_ip/net_ip.hpp" +#include "net_ip/basic_net_entity.hpp" +#include "net_ip/component/worker.hpp" +#include "asio.hpp" + +using io_context = asio::io_context; +using io_interface = chops::net::tcp_io_interface; +using const_buf = asio::const_buffer; +using endpoint = asio::ip::tcp::endpoint; + +const std::size_t HDR_SIZE = 4; // 1st 4 bytes of header is message size +const std::string PORT = "5002"; + +int main(int argc, char* argv[]) { + + bool print_errors = true; + + /* lambda handlers */ + // message handler + // receive text, convert to uppercase, send back to client + auto msg_hndlr = [&] (const_buf buf, io_interface iof, endpoint ep) { + return true; + }; + + auto msg_frame = [&] (asio::mutable_buffer buf) -> std::size_t { + return buf.size(); + }; + + auto io_state_chng_hndlr = [&] (io_interface iof, std::size_t n, bool flag) { + + if (flag) { + iof.start_io(HDR_SIZE, msg_hndlr, msg_frame); + } else { + iof.stop_io(); + } + + }; + + // error handler + auto err_func = [&] (io_interface iof, std::error_code err) { + if (print_errors) { + std::string err_text = err.category().name(); + err_text += ": " + std::to_string(err.value()) + ", " + + err.message(); + std::cerr << err_text << std::endl; + } + }; + + // work guard - handles @c std::thread and @c asio::io_context management + chops::net::worker wk; + wk.start(); + + // create @c net_ip instance + chops::net::net_ip echo_server(wk.get_io_context()); + chops::net::tcp_acceptor_net_entity net_entity_accept; + + // make @ tcp_acceptor, return @c network_entity + net_entity_accept = echo_server.make_tcp_acceptor(PORT.c_str()); + assert(net_entity_accept.is_valid()); + // start network entity, emplace handlers + net_entity_accept.start(io_state_chng_hndlr, err_func); + + std::cout << "Press return to exit" << std::endl; + + std::string s; + std::getline(std::cin, s); // pause until return + + net_entity_accept.stop(); + + wk.stop(); +} \ No newline at end of file From f444f2319bd1345660e67becb03edbc3f1fce006 Mon Sep 17 00:00:00 2001 From: Thurman Gillespy Date: Wed, 24 Apr 2019 11:24:20 -0700 Subject: [PATCH 2/6] 1st beta client & server --- example/echo_binary_text_client_demo.cpp | 144 +++++++++++++++++++++++ example/echo_binary_text_server_demo.cpp | 20 +++- 2 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 example/echo_binary_text_client_demo.cpp diff --git a/example/echo_binary_text_client_demo.cpp b/example/echo_binary_text_client_demo.cpp new file mode 100644 index 00000000..c616ad2b --- /dev/null +++ b/example/echo_binary_text_client_demo.cpp @@ -0,0 +1,144 @@ +/** + * @file + * + * @ingroup example_module + * + * @brief TCP connector (client) that sends binary text message to + * server, receives message back converted to upper case. + * + * @author Thurman Gillespy + * + * Copyright (c) Thurman Gillespy + * 4/23/19 + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + * Sample make file: +g++ -std=c++17 -Wall -Werror \ +-I ../include \ +-I ~/Projects/utility-rack/include/ \ +-I ~/Projects/asio/asio/include/ \ +-I ~/Projects/boost_1_69_0/ \ +echo_binary_text_client_demo.cpp -lpthread -o echo_client + * + */ + +#include +#include // EXIT_SUCCESS +#include // std::size_t +#include +#include +#include +#include + +#include "net_ip/net_ip.hpp" +#include "net_ip/basic_net_entity.hpp" +#include "net_ip/component/worker.hpp" +#include "asio.hpp" + +using io_context = asio::io_context; +using io_interface = chops::net::tcp_io_interface; +using const_buf = asio::const_buffer; +using endpoint = asio::ip::tcp::endpoint; + +const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size +const std::string PORT = "5002"; +const std::string IP_ADDR = "127.0.0.1"; + +io_interface tcp_iof; // use this to send text messages + +int main(int argc, char* argv[]) { + + bool print_errors = true; + + /* lambda handlers */ + // message handler + // receive text, convert to uppercase, send back to client + auto msg_hndlr = [&] (const_buf buf, io_interface iof, endpoint ep) { + std::cerr << "msg_hndlr: buf.size() = " << buf.size() << std::endl; + return true; + }; + + auto msg_frame = [&] (asio::mutable_buffer buf) -> std::size_t { + bool hdr_processed = false; + std::cerr << "msg_frame: buf.size() = " << buf.size(); + std::cerr << ", hdr_processed: " << (hdr_processed ? "true" : "false") << std::endl; + + if (hdr_processed) { + hdr_processed = false; + return 0; + } else { + hdr_processed = true; + return buf.size(); + } + }; + + auto io_state_chng_hndlr = [&] (io_interface iof, std::size_t n, bool flag) { + std::cerr << "io_state_chng_hndlr: flag = " << (flag ? "true" : "false") << std::endl; + + if (flag) { + iof.start_io(HDR_SIZE, msg_hndlr, msg_frame); + tcp_iof = iof; + } else { + iof.stop_io(); + } + + }; + + // error handler + auto err_func = [&] (io_interface iof, std::error_code err) { + if (print_errors) { + std::string err_text = err.category().name(); + err_text += ": " + std::to_string(err.value()) + ", " + + err.message(); + std::cerr << err_text << std::endl; + } + }; + + // work guard - handles @c std::thread and @c asio::io_context management + chops::net::worker wk; + wk.start(); + + // create @c net_ip instance + chops::net::net_ip echo_server(wk.get_io_context()); + chops::net::tcp_connector_net_entity net_entity_connect; + net_entity_connect = echo_server.make_tcp_connector(PORT.c_str(), IP_ADDR.c_str(), + std::chrono::milliseconds(5000)); + assert(net_entity_connect.is_valid()); + // start network entity, emplace handlers + net_entity_connect.start(io_state_chng_hndlr, err_func); + + std::cout << "binary text demo - client" << std::endl; + std::cout << "enter text to send, or \'quit\' to exit" << std::endl; + + bool shutdown = false; + std::string s; + while (!shutdown) { + std::getline (std::cin, s); // user input + if (s == "quit") { + shutdown = true; + continue; + } + // tcp.iof is not valid when there is no network connection + if (!tcp_iof.is_valid()) { + std::cout << "no connextion" << std::endl; + continue; // back to top of loop + } + + chops::mutable_shared_buffer buf; + + // 1st 2 bytes size of string + uint16_t size_val = (uint16_t)HDR_SIZE; + buf.append(&size_val, sizeof(size_val)); + buf.append(s.data(), s.size()); + std::cout << "buf.size() = " << buf.size() << std::endl; + tcp_iof.send(buf.data(), buf.size()); + } + + net_entity_connect.stop(); + + wk.stop(); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/example/echo_binary_text_server_demo.cpp b/example/echo_binary_text_server_demo.cpp index 1d546a7a..1e8cbdf1 100644 --- a/example/echo_binary_text_server_demo.cpp +++ b/example/echo_binary_text_server_demo.cpp @@ -41,8 +41,10 @@ using io_interface = chops::net::tcp_io_interface; using const_buf = asio::const_buffer; using endpoint = asio::ip::tcp::endpoint; -const std::size_t HDR_SIZE = 4; // 1st 4 bytes of header is message size +const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size const std::string PORT = "5002"; +io_interface tcp_iof; // use this to send text messages +bool hdr_processed = false; int main(int argc, char* argv[]) { @@ -52,17 +54,29 @@ int main(int argc, char* argv[]) { // message handler // receive text, convert to uppercase, send back to client auto msg_hndlr = [&] (const_buf buf, io_interface iof, endpoint ep) { + std::cerr << "msg_hndlr: buf.size() = " << buf.size() << std::endl; return true; }; auto msg_frame = [&] (asio::mutable_buffer buf) -> std::size_t { - return buf.size(); + std::cerr << "msg_frame: buf.size() = " << buf.size(); + std::cerr << ", hdr_processed: " << (hdr_processed ? "true" : "false") << std::endl; + + if (hdr_processed) { + hdr_processed = false; + return 0; + } else { + hdr_processed = true; + return buf.size(); + } }; auto io_state_chng_hndlr = [&] (io_interface iof, std::size_t n, bool flag) { + std::cerr << "io_state_chng_hndlr: flag = " << (flag ? "true" : "false") << std::endl; if (flag) { iof.start_io(HDR_SIZE, msg_hndlr, msg_frame); + tcp_iof = iof; } else { iof.stop_io(); } @@ -101,4 +115,6 @@ int main(int argc, char* argv[]) { net_entity_accept.stop(); wk.stop(); + + return EXIT_SUCCESS; } \ No newline at end of file From 0ace1c0773c132a33352627036b8861f5d6fbeb9 Mon Sep 17 00:00:00 2001 From: Thurman Gillespy Date: Wed, 24 Apr 2019 17:49:09 -0700 Subject: [PATCH 3/6] 1st working version echo_binary_text demos --- example/echo_binary_text_client_demo.cpp | 50 +++++++++++++----------- example/echo_binary_text_server_demo.cpp | 36 +++++++++++------ 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/example/echo_binary_text_client_demo.cpp b/example/echo_binary_text_client_demo.cpp index c616ad2b..b5c43cb3 100644 --- a/example/echo_binary_text_client_demo.cpp +++ b/example/echo_binary_text_client_demo.cpp @@ -35,7 +35,6 @@ echo_binary_text_client_demo.cpp -lpthread -o echo_client #include "net_ip/net_ip.hpp" #include "net_ip/basic_net_entity.hpp" #include "net_ip/component/worker.hpp" -#include "asio.hpp" using io_context = asio::io_context; using io_interface = chops::net::tcp_io_interface; @@ -46,40 +45,42 @@ const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size const std::string PORT = "5002"; const std::string IP_ADDR = "127.0.0.1"; -io_interface tcp_iof; // use this to send text messages - int main(int argc, char* argv[]) { - + io_interface tcp_iof; // use this to send text messages + bool hdr_processed = false; bool print_errors = true; /* lambda handlers */ + // message handler - // receive text, convert to uppercase, send back to client + // receive text, display to console auto msg_hndlr = [&] (const_buf buf, io_interface iof, endpoint ep) { - std::cerr << "msg_hndlr: buf.size() = " << buf.size() << std::endl; + // convert buf to string, but omit 1st 2 bytes (header) + std::string s (static_cast (buf.data()) + 2, buf.size() - 2); + std::cout << s << std::endl; + return true; }; auto msg_frame = [&] (asio::mutable_buffer buf) -> std::size_t { - bool hdr_processed = false; - std::cerr << "msg_frame: buf.size() = " << buf.size(); - std::cerr << ", hdr_processed: " << (hdr_processed ? "true" : "false") << std::endl; - + if (hdr_processed) { hdr_processed = false; return 0; } else { hdr_processed = true; - return buf.size(); + // 1st 2 bytes is message size + uint16_t size = *(static_cast (buf.data())); + + return size; } }; auto io_state_chng_hndlr = [&] (io_interface iof, std::size_t n, bool flag) { - std::cerr << "io_state_chng_hndlr: flag = " << (flag ? "true" : "false") << std::endl; - + if (flag) { iof.start_io(HDR_SIZE, msg_hndlr, msg_frame); - tcp_iof = iof; + tcp_iof = iof; // used later to send text } else { iof.stop_io(); } @@ -102,6 +103,7 @@ int main(int argc, char* argv[]) { // create @c net_ip instance chops::net::net_ip echo_server(wk.get_io_context()); + chops::net::tcp_connector_net_entity net_entity_connect; net_entity_connect = echo_server.make_tcp_connector(PORT.c_str(), IP_ADDR.c_str(), std::chrono::milliseconds(5000)); @@ -109,11 +111,11 @@ int main(int argc, char* argv[]) { // start network entity, emplace handlers net_entity_connect.start(io_state_chng_hndlr, err_func); - std::cout << "binary text demo - client" << std::endl; - std::cout << "enter text to send, or \'quit\' to exit" << std::endl; + std::cout << "chops-net-ip binary text echo demo - client" << std::endl; + std::cout << "Enter text to send, or \'quit\' to exit" << std::endl; - bool shutdown = false; std::string s; + bool shutdown = false; while (!shutdown) { std::getline (std::cin, s); // user input if (s == "quit") { @@ -122,20 +124,22 @@ int main(int argc, char* argv[]) { } // tcp.iof is not valid when there is no network connection if (!tcp_iof.is_valid()) { - std::cout << "no connextion" << std::endl; + std::cout << "no connection..." << std::endl; continue; // back to top of loop } + // create buffer to send entered message from user chops::mutable_shared_buffer buf; - // 1st 2 bytes size of string - uint16_t size_val = (uint16_t)HDR_SIZE; - buf.append(&size_val, sizeof(size_val)); - buf.append(s.data(), s.size()); - std::cout << "buf.size() = " << buf.size() << std::endl; + // 1st 2 bytes size of message are the string length + uint16_t size_val = s.size(); + buf.append(&size_val, sizeof(size_val)); // put 2 bytes into buffer + buf.append(s.data(), s.size()); // now add the string + // send message to server (TCP_acceptor) tcp_iof.send(buf.data(), buf.size()); } + // cleanup net_entity_connect.stop(); wk.stop(); diff --git a/example/echo_binary_text_server_demo.cpp b/example/echo_binary_text_server_demo.cpp index 1e8cbdf1..fd3118ea 100644 --- a/example/echo_binary_text_server_demo.cpp +++ b/example/echo_binary_text_server_demo.cpp @@ -43,40 +43,53 @@ using endpoint = asio::ip::tcp::endpoint; const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size const std::string PORT = "5002"; -io_interface tcp_iof; // use this to send text messages -bool hdr_processed = false; int main(int argc, char* argv[]) { - + io_interface tcp_iof; // use this to send text messages + bool hdr_processed = false; bool print_errors = true; /* lambda handlers */ // message handler // receive text, convert to uppercase, send back to client auto msg_hndlr = [&] (const_buf buf, io_interface iof, endpoint ep) { - std::cerr << "msg_hndlr: buf.size() = " << buf.size() << std::endl; + // create string from buf, omit 1st 2 bytes (header) + std::string s (static_cast (buf.data()) + 2, buf.size() - 2); + + // convert to uppercase + auto to_upper = [] (char& c) { c = ::toupper(c); }; + std::for_each(s.begin(), s.end(), to_upper); + + // create buffer to send test data + chops::mutable_shared_buffer buf_out; + // 1st 2 bytes are the size of the message + uint16_t size_val = s.size(); + buf_out.append(&size_val, sizeof(size_val)); + buf_out.append(s.data(), s.size()); + + iof.send(buf_out.data(), buf_out.size()); + return true; }; auto msg_frame = [&] (asio::mutable_buffer buf) -> std::size_t { - std::cerr << "msg_frame: buf.size() = " << buf.size(); - std::cerr << ", hdr_processed: " << (hdr_processed ? "true" : "false") << std::endl; - + if (hdr_processed) { hdr_processed = false; return 0; } else { hdr_processed = true; - return buf.size(); + // 1st 2 bytes is message size + uint16_t size = *(static_cast (buf.data())); + + return size; } }; auto io_state_chng_hndlr = [&] (io_interface iof, std::size_t n, bool flag) { - std::cerr << "io_state_chng_hndlr: flag = " << (flag ? "true" : "false") << std::endl; - + if (flag) { iof.start_io(HDR_SIZE, msg_hndlr, msg_frame); - tcp_iof = iof; } else { iof.stop_io(); } @@ -107,6 +120,7 @@ int main(int argc, char* argv[]) { // start network entity, emplace handlers net_entity_accept.start(io_state_chng_hndlr, err_func); + std::cout << "chops-net-ip binary text echo demo - server" << std::endl; std::cout << "Press return to exit" << std::endl; std::string s; From 1b07a74caab828830359f9617dcb164fdcc9f831 Mon Sep 17 00:00:00 2001 From: Thurman Gillespy Date: Thu, 25 Apr 2019 09:48:16 -0700 Subject: [PATCH 4/6] code/header cleanup; command line args; server display client info --- example/echo_binary_text_client_demo.cpp | 86 +++++++++++++++++++++--- example/echo_binary_text_server_demo.cpp | 67 +++++++++++++++--- 2 files changed, 131 insertions(+), 22 deletions(-) diff --git a/example/echo_binary_text_client_demo.cpp b/example/echo_binary_text_client_demo.cpp index b5c43cb3..79630d9b 100644 --- a/example/echo_binary_text_client_demo.cpp +++ b/example/echo_binary_text_client_demo.cpp @@ -9,7 +9,7 @@ * @author Thurman Gillespy * * Copyright (c) Thurman Gillespy - * 4/23/19 + * 4/25/19 * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -43,26 +43,83 @@ using endpoint = asio::ip::tcp::endpoint; const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size const std::string PORT = "5002"; -const std::string IP_ADDR = "127.0.0.1"; +const std::string LOCAL_LOOP = "127.0.0.1"; + +// process command line args (if any) +bool process_args(int argc, char* argv[], bool& print_errors, std::string& ip_address, + std::string& port) { + + const std::string HELP = "-h"; + const std::string PRINT_ERRS = "-e"; + const std::string usage = \ + "useage: ./echo_client [-h | -e] [ip address/hostname] [port]\n" + " -h Print useage\n" + " -e Print error messages\n" + " ip address Default: 127.0.0.1 (LOCAL LOOP)\n" + " port Default port: 5002\n" + " change port and use local loop:\n" + " ./echo_client [e] \"\" port"; + + int offset = 0; + + if (argc > 4 || (argc > 1 && argv[1] == HELP)) { + std::cout << usage << std::endl; + return EXIT_FAILURE; + } + + if (argc > 1 && argv[1] == PRINT_ERRS) { + print_errors = true; + offset = 1; + } + + if (argc == 2 + offset) { + ip_address = argv[1 + offset]; + } else if (argc == 3 + offset) { + ip_address = argv[1 + offset]; + port = argv[2 + offset]; + } else if (argc > 3 + offset) { + std::cout << usage << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + int main(int argc, char* argv[]) { - io_interface tcp_iof; // use this to send text messages + std::string ip_address = LOCAL_LOOP; + std::string port = PORT; bool hdr_processed = false; - bool print_errors = true; + bool print_errors = false; + io_interface tcp_iof; // use this to send text messages + + if (process_args(argc, argv, print_errors, ip_address, port) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + // // DEBUG + // std::cout << "argc: " << argc << std::endl; + // std::cout << "print errors: " << (print_errors ? "true" : "false") << std::endl; + // std::cout << "ip address: " << ip_address << ", port: " << port << std::endl; + // std::cout << std::endl; + // return 1; /* lambda handlers */ // message handler // receive text, display to console auto msg_hndlr = [&] (const_buf buf, io_interface iof, endpoint ep) { - // convert buf to string, but omit 1st 2 bytes (header) + // create string from buf, omit 1st 2 bytes (header) std::string s (static_cast (buf.data()) + 2, buf.size() - 2); std::cout << s << std::endl; return true; }; - auto msg_frame = [&] (asio::mutable_buffer buf) -> std::size_t { + // message frame handler + // 1st call: buffer contains only the header, return message size, toggle flag + // 2nd call: return 0 to indicate no further prodessing, toggle flag + auto msg_frame = [&hdr_processed] (asio::mutable_buffer buf) -> std::size_t { if (hdr_processed) { hdr_processed = false; @@ -76,11 +133,12 @@ int main(int argc, char* argv[]) { } }; + // io state change handler auto io_state_chng_hndlr = [&] (io_interface iof, std::size_t n, bool flag) { if (flag) { iof.start_io(HDR_SIZE, msg_hndlr, msg_frame); - tcp_iof = iof; // used later to send text + tcp_iof = iof; // return iof to main, used later to send text } else { iof.stop_io(); } @@ -102,18 +160,25 @@ int main(int argc, char* argv[]) { wk.start(); // create @c net_ip instance - chops::net::net_ip echo_server(wk.get_io_context()); + chops::net::net_ip echo_client(wk.get_io_context()); + // creae a network entity chops::net::tcp_connector_net_entity net_entity_connect; - net_entity_connect = echo_server.make_tcp_connector(PORT.c_str(), IP_ADDR.c_str(), + net_entity_connect = echo_client.make_tcp_connector(port.c_str(), ip_address.c_str(), std::chrono::milliseconds(5000)); assert(net_entity_connect.is_valid()); // start network entity, emplace handlers net_entity_connect.start(io_state_chng_hndlr, err_func); + // begin std::cout << "chops-net-ip binary text echo demo - client" << std::endl; + std::cout << " IP address:port = " << (ip_address == "" ? LOCAL_LOOP : ip_address); + std::cout << ":" << port << std::endl; + std::cout << " print error messages: " << (print_errors ? "ON" : "OFF") << std::endl; std::cout << "Enter text to send, or \'quit\' to exit" << std::endl; + + // get text to send from user, exit on 'quit' std::string s; bool shutdown = false; while (!shutdown) { @@ -128,7 +193,7 @@ int main(int argc, char* argv[]) { continue; // back to top of loop } - // create buffer to send entered message from user + // buffer to send entered message from user chops::mutable_shared_buffer buf; // 1st 2 bytes size of message are the string length @@ -141,7 +206,6 @@ int main(int argc, char* argv[]) { // cleanup net_entity_connect.stop(); - wk.stop(); return EXIT_SUCCESS; diff --git a/example/echo_binary_text_server_demo.cpp b/example/echo_binary_text_server_demo.cpp index fd3118ea..33c9a161 100644 --- a/example/echo_binary_text_server_demo.cpp +++ b/example/echo_binary_text_server_demo.cpp @@ -9,7 +9,7 @@ * @author Thurman Gillespy * * Copyright (c) Thurman Gillespy - * 4/23/19 + * 4/25/19 * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -44,18 +44,57 @@ using endpoint = asio::ip::tcp::endpoint; const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size const std::string PORT = "5002"; +bool processArgs(int argc, char* argv[], bool& print_errors, std::string& port) { + const std::string HELP = "-h"; + const std::string PRINT_ERRS = "-e"; + const std::string usage = \ + "useage: ./echo_server [-h | -e] [port]\n" + " -h Print useage\n" + " -e Print error messages\n" + " port Default port: 5002"; + int offset = 0; + + if (argc > 3 || (argc > 1 && argv[1] == HELP)) { + std::cout << usage << std::endl; + return EXIT_FAILURE; + } + + if (argc > 1 && argv[1] == PRINT_ERRS) { + print_errors = true; + offset = 1; + } + + if (argc > 1 + offset) { + port = argv[1 + offset]; + } + + return EXIT_SUCCESS; +} + int main(int argc, char* argv[]) { - io_interface tcp_iof; // use this to send text messages + std::string port = PORT; bool hdr_processed = false; - bool print_errors = true; + bool print_errors = false; + + if (processArgs(argc, argv, print_errors, port) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + // // DEBUG + // std::cout << "argc: " << argc << std::endl; + // std::cout << "port: " << port << "; print errors: " << (print_errors ? "true" : "false"); + // std::cout << std::endl; + // return 1; - /* lambda handlers */ + /**** lambda handlers ****/ + // message handler // receive text, convert to uppercase, send back to client auto msg_hndlr = [&] (const_buf buf, io_interface iof, endpoint ep) { // create string from buf, omit 1st 2 bytes (header) std::string s (static_cast (buf.data()) + 2, buf.size() - 2); - + // print info about client + std::cout << "received request from " << ep.address() << ":" << ep.port() << std::endl; + std::cout << " text: " << s << std::endl; // convert to uppercase auto to_upper = [] (char& c) { c = ::toupper(c); }; std::for_each(s.begin(), s.end(), to_upper); @@ -64,15 +103,18 @@ int main(int argc, char* argv[]) { chops::mutable_shared_buffer buf_out; // 1st 2 bytes are the size of the message uint16_t size_val = s.size(); - buf_out.append(&size_val, sizeof(size_val)); - buf_out.append(s.data(), s.size()); + buf_out.append(&size_val, sizeof(size_val)); // write 2 byte size + buf_out.append(s.data(), s.size()); // now add the text data iof.send(buf_out.data(), buf_out.size()); return true; }; - auto msg_frame = [&] (asio::mutable_buffer buf) -> std::size_t { + // message frame handler + // 1st call: buffer contains only the header, return message size, toggle flag + // 2nd call: return 0 to indicate no further prodessing, toggle flag + auto msg_frame = [&hdr_processed] (asio::mutable_buffer buf) -> std::size_t { if (hdr_processed) { hdr_processed = false; @@ -86,6 +128,7 @@ int main(int argc, char* argv[]) { } }; + // io state change handler auto io_state_chng_hndlr = [&] (io_interface iof, std::size_t n, bool flag) { if (flag) { @@ -115,19 +158,21 @@ int main(int argc, char* argv[]) { chops::net::tcp_acceptor_net_entity net_entity_accept; // make @ tcp_acceptor, return @c network_entity - net_entity_accept = echo_server.make_tcp_acceptor(PORT.c_str()); + net_entity_accept = echo_server.make_tcp_acceptor(port.c_str()); assert(net_entity_accept.is_valid()); // start network entity, emplace handlers net_entity_accept.start(io_state_chng_hndlr, err_func); std::cout << "chops-net-ip binary text echo demo - server" << std::endl; + std::cout << " IP address:port = 127.0.0.1:" << port << std::endl; + std::cout << " print error messages: " << (print_errors ? "ON" : "OFF") << std::endl; std::cout << "Press return to exit" << std::endl; std::string s; std::getline(std::cin, s); // pause until return - + + // cleanup net_entity_accept.stop(); - wk.stop(); return EXIT_SUCCESS; From 598446f1e5cd6a5ebfca6131b767129d427f51d0 Mon Sep 17 00:00:00 2001 From: Thurman Gillespy Date: Thu, 25 Apr 2019 10:01:07 -0700 Subject: [PATCH 5/6] debug code removal --- example/echo_binary_text_client_demo.cpp | 11 ++--------- example/echo_binary_text_server_demo.cpp | 5 ----- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/example/echo_binary_text_client_demo.cpp b/example/echo_binary_text_client_demo.cpp index 79630d9b..fe50ab45 100644 --- a/example/echo_binary_text_client_demo.cpp +++ b/example/echo_binary_text_client_demo.cpp @@ -96,15 +96,8 @@ int main(int argc, char* argv[]) { if (process_args(argc, argv, print_errors, ip_address, port) == EXIT_FAILURE) { return EXIT_FAILURE; } - - // // DEBUG - // std::cout << "argc: " << argc << std::endl; - // std::cout << "print errors: " << (print_errors ? "true" : "false") << std::endl; - // std::cout << "ip address: " << ip_address << ", port: " << port << std::endl; - // std::cout << std::endl; - // return 1; - - /* lambda handlers */ + + /**** lambda handlers ****/ // message handler // receive text, display to console diff --git a/example/echo_binary_text_server_demo.cpp b/example/echo_binary_text_server_demo.cpp index 33c9a161..b0388a89 100644 --- a/example/echo_binary_text_server_demo.cpp +++ b/example/echo_binary_text_server_demo.cpp @@ -79,11 +79,6 @@ int main(int argc, char* argv[]) { if (processArgs(argc, argv, print_errors, port) == EXIT_FAILURE) { return EXIT_FAILURE; } - // // DEBUG - // std::cout << "argc: " << argc << std::endl; - // std::cout << "port: " << port << "; print errors: " << (print_errors ? "true" : "false"); - // std::cout << std::endl; - // return 1; /**** lambda handlers ****/ From 768c0771a92b85edce2e072d5e2c0f70e484fe8e Mon Sep 17 00:00:00 2001 From: Thurman Gillespy Date: Thu, 25 Apr 2019 11:15:21 -0700 Subject: [PATCH 6/6] changed scope of lamda captures --- example/echo_binary_text_client_demo.cpp | 18 +++++++++--------- example/echo_binary_text_server_demo.cpp | 11 ++++++----- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/example/echo_binary_text_client_demo.cpp b/example/echo_binary_text_client_demo.cpp index fe50ab45..3d121b37 100644 --- a/example/echo_binary_text_client_demo.cpp +++ b/example/echo_binary_text_client_demo.cpp @@ -41,14 +41,9 @@ using io_interface = chops::net::tcp_io_interface; using const_buf = asio::const_buffer; using endpoint = asio::ip::tcp::endpoint; -const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size -const std::string PORT = "5002"; -const std::string LOCAL_LOOP = "127.0.0.1"; - // process command line args (if any) bool process_args(int argc, char* argv[], bool& print_errors, std::string& ip_address, std::string& port) { - const std::string HELP = "-h"; const std::string PRINT_ERRS = "-e"; const std::string usage = \ @@ -87,6 +82,10 @@ bool process_args(int argc, char* argv[], bool& print_errors, std::string& ip_ad int main(int argc, char* argv[]) { + const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size + const std::string PORT = "5002"; + const std::string LOCAL_LOOP = "127.0.0.1"; + std::string ip_address = LOCAL_LOOP; std::string port = PORT; bool hdr_processed = false; @@ -96,12 +95,12 @@ int main(int argc, char* argv[]) { if (process_args(argc, argv, print_errors, ip_address, port) == EXIT_FAILURE) { return EXIT_FAILURE; } - + /**** lambda handlers ****/ // message handler // receive text, display to console - auto msg_hndlr = [&] (const_buf buf, io_interface iof, endpoint ep) { + auto msg_hndlr = [] (const_buf buf, io_interface iof, endpoint ep) { // create string from buf, omit 1st 2 bytes (header) std::string s (static_cast (buf.data()) + 2, buf.size() - 2); std::cout << s << std::endl; @@ -127,7 +126,8 @@ int main(int argc, char* argv[]) { }; // io state change handler - auto io_state_chng_hndlr = [&] (io_interface iof, std::size_t n, bool flag) { + auto io_state_chng_hndlr = [&msg_hndlr, &msg_frame, &tcp_iof] + (io_interface iof, std::size_t n, bool flag) { if (flag) { iof.start_io(HDR_SIZE, msg_hndlr, msg_frame); @@ -139,7 +139,7 @@ int main(int argc, char* argv[]) { }; // error handler - auto err_func = [&] (io_interface iof, std::error_code err) { + auto err_func = [&print_errors] (io_interface iof, std::error_code err) { if (print_errors) { std::string err_text = err.category().name(); err_text += ": " + std::to_string(err.value()) + ", " + diff --git a/example/echo_binary_text_server_demo.cpp b/example/echo_binary_text_server_demo.cpp index b0388a89..fb90a4da 100644 --- a/example/echo_binary_text_server_demo.cpp +++ b/example/echo_binary_text_server_demo.cpp @@ -41,9 +41,6 @@ using io_interface = chops::net::tcp_io_interface; using const_buf = asio::const_buffer; using endpoint = asio::ip::tcp::endpoint; -const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size -const std::string PORT = "5002"; - bool processArgs(int argc, char* argv[], bool& print_errors, std::string& port) { const std::string HELP = "-h"; const std::string PRINT_ERRS = "-e"; @@ -72,6 +69,9 @@ bool processArgs(int argc, char* argv[], bool& print_errors, std::string& port) } int main(int argc, char* argv[]) { + const std::size_t HDR_SIZE = 2; // 1st 2 bytes of header is message size + const std::string PORT = "5002"; + std::string port = PORT; bool hdr_processed = false; bool print_errors = false; @@ -84,7 +84,7 @@ int main(int argc, char* argv[]) { // message handler // receive text, convert to uppercase, send back to client - auto msg_hndlr = [&] (const_buf buf, io_interface iof, endpoint ep) { + auto msg_hndlr = [] (const_buf buf, io_interface iof, endpoint ep) { // create string from buf, omit 1st 2 bytes (header) std::string s (static_cast (buf.data()) + 2, buf.size() - 2); // print info about client @@ -124,7 +124,8 @@ int main(int argc, char* argv[]) { }; // io state change handler - auto io_state_chng_hndlr = [&] (io_interface iof, std::size_t n, bool flag) { + auto io_state_chng_hndlr = [&msg_hndlr, &msg_frame] + (io_interface iof, std::size_t n, bool flag) { if (flag) { iof.start_io(HDR_SIZE, msg_hndlr, msg_frame);