| src/examples/cpp03/chat/chat_client.cpp | src/examples/cpp11/chat/chat_client.cpp | 
| ⋮ | ⋮ | 
| 1  | // | 1  | // | 
| 2  | //·chat_client.cpp | 2  | //·chat_client.cpp | 
| 3  | //·~~~~~~~~~~~~~~~ | 3  | //·~~~~~~~~~~~~~~~ | 
| 4  | // | 4  | // | 
| 5  | //·Copyright·(c)·2003-2018·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 5  | //·Copyright·(c)·2003-2018·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 
| 6  | // | 6  | // | 
| 7  | //·Distributed·under·the·Boost·Software·License,·Version·1.0.·(See·accompanying | 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) | 8  | //·file·LICENSE_1_0.txt·or·copy·at·http://www.boost.org/LICENSE_1_0.txt) | 
| 9  | // | 9  | // | 
| 10  |  | 10  |  | 
| 11  | #include·<cstdlib> | 11  | #include·<cstdlib> | 
| 12  | #include·<deque> | 12  | #include·<deque> | 
| 13  | #include·<iostream> | 13  | #include·<iostream> | 
| 14  | #include·<boost/bind.hpp> | 14  | #include·<thread> | 
| 15  | #include·"asio.hpp" | 15  | #include·"asio.hpp" | 
| 16  | #include·"chat_message.hpp" | 16  | #include·"chat_message.hpp" | 
| 17  |  | 17  |  | 
| 18  | using·asio::ip::tcp; | 18  | using·asio::ip::tcp; | 
| 19  |  | 19  |  | 
| 20  | typedef·std::deque<chat_message>·chat_message_queue; | 20  | typedef·std::deque<chat_message>·chat_message_queue; | 
| 21  |  | 21  |  | 
| 22  | class·chat_client | 22  | class·chat_client | 
| 23  | { | 23  | { | 
| 24  | public: | 24  | public: | 
| 25  | ··chat_client(asio::io_context&·io_context, | 25  | ··chat_client(asio::io_context&·io_context, | 
| 26  | ······const·tcp::resolver::results_type&·endpoints) | 26  | ······const·tcp::resolver::results_type&·endpoints) | 
| 27  | ····:·io_context_(io_context), | 27  | ····:·io_context_(io_context), | 
| 28  | ······socket_(io_context) | 28  | ······socket_(io_context) | 
| 29  | ··{ | 29  | ··{ | 
| 30  | ····asio::async_connect(socket_,·endpoints, | 30  | ····do_connect(endpoints); | 
| 31  | ········boost::bind(&chat_client::handle_connect,·this, |  | 
| 32  | ··········asio::placeholders::error)); |  | 
| 33  | ··} | 31  | ··} | 
| 34  |  | 32  |  | 
| 35  | ··void·write(const·chat_message&·msg) | 33  | ··void·write(const·chat_message&·msg) | 
| 36  | ··{ | 34  | ··{ | 
| 37  | ····asio::post(io_context_, | 35  | ····asio::post(io_context_, | 
| 38  | ········boost::bind(&chat_client::do_write,·this,·msg)); | 36  | ········[this,·msg]() | 
|   | 37  | ········{ | 
|   | 38  | ··········bool·write_in_progress·=·!write_msgs_.empty(); | 
|   | 39  | ··········write_msgs_.push_back(msg); | 
|   | 40  | ··········if·(!write_in_progress) | 
|   | 41  | ··········{ | 
|   | 42  | ············do_write(); | 
|   | 43  | ··········} | 
|   | 44  | ········}); | 
| 39  | ··} | 45  | ··} | 
| 40  |  | 46  |  | 
| 41  | ··void·close() | 47  | ··void·close() | 
| 42  | ··{ | 48  | ··{ | 
| 43  | ····asio::post(io_context_, | 49  | ····asio::post(io_context_,·[this]()·{·socket_.close();·}); | 
| 44  | ········boost::bind(&chat_client::do_close,·this)); |  | 
| 45  | ··} | 50  | ··} | 
| 46  |  | 51  |  | 
| 47  | private: | 52  | private: | 
| 48  |  | 53  | ··void·do_connect(const·tcp::resolver::results_type&·endpoints) | 
| 49  | ··void·handle_connect(const·asio::error_code&·error) |  | 
| 50  | ··{ |  | 
| 51  | ····if·(!error) |  | 
| 52  | ····{ |  | 
| 53  | ······asio::async_read(socket_, |  | 
| 54  | ··········asio::buffer(read_msg_.data(),·chat_message::header_length), |  | 
| 55  | ··········boost::bind(&chat_client::handle_read_header,·this, |  | 
| 56  | ············asio::placeholders::error)); |  | 
| 57  | ····} |  | 
| 58  | ··} |  | 
| 59  |  |  | 
| 60  | ··void·handle_read_header(const·asio::error_code&·error) |  | 
| 61  | ··{ |  | 
| 62  | ····if·(!error·&&·read_msg_.decode_header()) |  | 
| 63  | ····{ |  | 
| 64  | ······asio::async_read(socket_, |  | 
| 65  | ··········asio::buffer(read_msg_.body(),·read_msg_.body_length()), |  | 
| 66  | ··········boost::bind(&chat_client::handle_read_body,·this, |  | 
| 67  | ············asio::placeholders::error)); |  | 
| 68  | ····} |  | 
| 69  | ····else |  | 
| 70  | ····{ |  | 
| 71  | ······do_close(); |  | 
| 72  | ····} |  | 
| 73  | ··} |  | 
| 74  |  |  | 
| 75  | ··void·handle_read_body(const·asio::error_code&·error) |  | 
| 76  | ··{ |  | 
| 77  | ····if·(!error) |  | 
| 78  | ····{ |  | 
| 79  | ······std::cout.write(read_msg_.body(),·read_msg_.body_length()); |  | 
| 80  | ······std::cout·<<·"\n"; |  | 
| 81  | ······asio::async_read(socket_, |  | 
| 82  | ··········asio::buffer(read_msg_.data(),·chat_message::header_length), |  | 
| 83  | ··········boost::bind(&chat_client::handle_read_header,·this, |  | 
| 84  | ············asio::placeholders::error)); |  | 
| 85  | ····} |  | 
| 86  | ····else |  | 
| 87  | ····{ |  | 
| 88  | ······do_close(); |  | 
| 89  | ····} |  | 
| 90  | ··} |  | 
| 91  |  |  | 
| 92  | ··void·do_write(chat_message·msg) |  | 
| 93  | ··{ |  | 
| 94  | ····bool·write_in_progress·=·!write_msgs_.empty(); |  | 
| 95  | ····write_msgs_.push_back(msg); |  | 
| 96  | ····if·(!write_in_progress) |  | 
| 97  | ····{ |  | 
| 98  | ······asio::async_write(socket_, |  | 
| 99  | ··········asio::buffer(write_msgs_.front().data(), |  | 
| 100  | ············write_msgs_.front().length()), |  | 
| 101  | ··········boost::bind(&chat_client::handle_write,·this, |  | 
| 102  | ············asio::placeholders::error)); |  | 
| 103  | ····} |  | 
| 104  | ··} |  | 
| 105  |  |  | 
| 106  | ··void·handle_write(const·asio::error_code&·error) |  | 
| 107  | ··{ | 54  | ··{ | 
| 108  | ····if·(!error) | 55  | ····asio::async_connect(socket_,·endpoints, | 
| 109  | ····{ | 56  | ········[this](std::error_code·ec,·tcp::endpoint) | 
| 110  | ······write_msgs_.pop_front(); | 57  | ········{ | 
| 111  | ······if·(!write_msgs_.empty()) | 58  | ··········if·(!ec) | 
| 112  | ······{ | 59  | ··········{ | 
| 113  | ········asio::async_write(socket_, | 60  | ············do_read_header(); | 
| 114  | ············asio::buffer(write_msgs_.front().data(), | 61  | ··········} | 
| 115  | ··············write_msgs_.front().length()), | 62  | ········}); | 
| 116  | ············boost::bind(&chat_client::handle_write,·this, | 63  | ··} | 
| 117  | ··············asio::placeholders::error)); | 64  |  | 
| 118  | ······} | 65  | ··void·do_read_header() | 
| 119  | ····} | 66  | ··{ | 
| 120  | ····else | 67  | ····asio::async_read(socket_, | 
| 121  | ····{ | 68  | ········asio::buffer(read_msg_.data(),·chat_message::header_length), | 
| 122  | ······do_close(); | 69  | ········[this](std::error_code·ec,·std::size_t·/*length*/) | 
| 123  | ····} | 70  | ········{ | 
| 124  | ··} | 71  | ··········if·(!ec·&&·read_msg_.decode_header()) | 
| 125  |  | 72  | ··········{ | 
| 126  | ··void·do_close() | 73  | ············do_read_body(); | 
| 127  | ··{ | 74  | ··········} | 
| 128  | ····socket_.close(); | 75  | ··········else | 
|   | 76  | ··········{ | 
|   | 77  | ············socket_.close(); | 
|   | 78  | ··········} | 
|   | 79  | ········}); | 
|   | 80  | ··} | 
|   | 81  |  | 
|   | 82  | ··void·do_read_body() | 
|   | 83  | ··{ | 
|   | 84  | ····asio::async_read(socket_, | 
|   | 85  | ········asio::buffer(read_msg_.body(),·read_msg_.body_length()), | 
|   | 86  | ········[this](std::error_code·ec,·std::size_t·/*length*/) | 
|   | 87  | ········{ | 
|   | 88  | ··········if·(!ec) | 
|   | 89  | ··········{ | 
|   | 90  | ············std::cout.write(read_msg_.body(),·read_msg_.body_length()); | 
|   | 91  | ············std::cout·<<·"\n"; | 
|   | 92  | ············do_read_header(); | 
|   | 93  | ··········} | 
|   | 94  | ··········else | 
|   | 95  | ··········{ | 
|   | 96  | ············socket_.close(); | 
|   | 97  | ··········} | 
|   | 98  | ········}); | 
|   | 99  | ··} | 
|   | 100  |  | 
|   | 101  | ··void·do_write() | 
|   | 102  | ··{ | 
|   | 103  | ····asio::async_write(socket_, | 
|   | 104  | ········asio::buffer(write_msgs_.front().data(), | 
|   | 105  | ··········write_msgs_.front().length()), | 
|   | 106  | ········[this](std::error_code·ec,·std::size_t·/*length*/) | 
|   | 107  | ········{ | 
|   | 108  | ··········if·(!ec) | 
|   | 109  | ··········{ | 
|   | 110  | ············write_msgs_.pop_front(); | 
|   | 111  | ············if·(!write_msgs_.empty()) | 
|   | 112  | ············{ | 
|   | 113  | ··············do_write(); | 
|   | 114  | ············} | 
|   | 115  | ··········} | 
|   | 116  | ··········else | 
|   | 117  | ··········{ | 
|   | 118  | ············socket_.close(); | 
|   | 119  | ··········} | 
|   | 120  | ········}); | 
| 129  | ··} | 121  | ··} | 
| 130  |  | 122  |  | 
| 131  | private: | 123  | private: | 
| 132  | ··asio::io_context&·io_context_; | 124  | ··asio::io_context&·io_context_; | 
| 133  | ··tcp::socket·socket_; | 125  | ··tcp::socket·socket_; | 
| 134  | ··chat_message·read_msg_; | 126  | ··chat_message·read_msg_; | 
| 135  | ··chat_message_queue·write_msgs_; | 127  | ··chat_message_queue·write_msgs_; | 
| 136  | }; | 128  | }; | 
| 137  |  | 129  |  | 
| 138  | int·main(int·argc,·char*·argv[]) | 130  | int·main(int·argc,·char*·argv[]) | 
| 139  | { | 131  | { | 
| 140  | ··try | 132  | ··try | 
| 141  | ··{ | 133  | ··{ | 
| 142  | ····if·(argc·!=·3) | 134  | ····if·(argc·!=·3) | 
| 143  | ····{ | 135  | ····{ | 
| 144  | ······std::cerr·<<·"Usage:·chat_client·<host>·<port>\n"; | 136  | ······std::cerr·<<·"Usage:·chat_client·<host>·<port>\n"; | 
| 145  | ······return·1; | 137  | ······return·1; | 
| 146  | ····} | 138  | ····} | 
| 147  |  | 139  |  | 
| 148  | ····asio::io_context·io_context; | 140  | ····asio::io_context·io_context; | 
| 149  |  | 141  |  | 
| 150  | ····tcp::resolver·resolver(io_context); | 142  | ····tcp::resolver·resolver(io_context); | 
| 151  | ····tcp::resolver::results_type·endpoints·=·resolver.resolve(argv[1],·argv[2]); | 143  | ····auto·endpoints·=·resolver.resolve(argv[1],·argv[2]); | 
| 152  |  |  | 
| 153  | ····chat_client·c(io_context,·endpoints); | 144  | ····chat_client·c(io_context,·endpoints); | 
| 154  |  | 145  |  | 
| 155  | ····asio::thread·t(boost::bind(&asio::io_context::run,·&io_context)); | 146  | ····std::thread·t([&io_context](){·io_context.run();·}); | 
| 156  |  | 147  |  | 
| 157  | ····char·line[chat_message::max_body_length·+·1]; | 148  | ····char·line[chat_message::max_body_length·+·1]; | 
| 158  | ····while·(std::cin.getline(line,·chat_message::max_body_length·+·1)) | 149  | ····while·(std::cin.getline(line,·chat_message::max_body_length·+·1)) | 
| 159  | ····{ | 150  | ····{ | 
| 160  | ······using·namespace·std;·//·For·strlen·and·memcpy. |  | 
| 161  | ······chat_message·msg; | 151  | ······chat_message·msg; | 
| 162  | ······msg.body_length(strlen(line)); | 152  | ······msg.body_length(std::strlen(line)); | 
| 163  | ······memcpy(msg.body(),·line,·msg.body_length()); | 153  | ······std::memcpy(msg.body(),·line,·msg.body_length()); | 
| 164  | ······msg.encode_header(); | 154  | ······msg.encode_header(); | 
| 165  | ······c.write(msg); | 155  | ······c.write(msg); | 
| 166  | ····} | 156  | ····} | 
| 167  |  | 157  |  | 
| 168  | ····c.close(); | 158  | ····c.close(); | 
| 169  | ····t.join(); | 159  | ····t.join(); | 
| 170  | ··} | 160  | ··} | 
| 171  | ··catch·(std::exception&·e) | 161  | ··catch·(std::exception&·e) | 
| 172  | ··{ | 162  | ··{ | 
| 173  | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; | 163  | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; | 
| 174  | ··} | 164  | ··} | 
| 175  |  | 165  |  | 
| 176  | ··return·0; | 166  | ··return·0; | 
| 177  | } | 167  | } |