-
Notifications
You must be signed in to change notification settings - Fork 0
/
ChatClient.cpp
129 lines (111 loc) · 3.24 KB
/
ChatClient.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#define _CRT_SECURE_NO_WARNINGS
#include <cstdlib>
#include <deque>
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include "chat_message.h"
using boost::asio::ip::tcp;
typedef std::deque<chat_message> chat_message_queue;
class chat_client {
public:
chat_client(boost::asio::io_context& io_context,
const tcp::resolver::results_type& endpoints)
: io_context_(io_context), socket_(io_context) {
do_connect(endpoints);
}
void write(const chat_message& msg) {
boost::asio::post(io_context_, [this, msg]() {
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress) {
do_write();
}
});
}
void close() {
boost::asio::post(io_context_, [this]() { socket_.close(); });
}
private:
void do_connect(const tcp::resolver::results_type& endpoints) {
boost::asio::async_connect(
socket_, endpoints,
[this](boost::system::error_code ec, tcp::endpoint) {
if (!ec) {
do_read_header();
}
});
}
void do_read_header() {
boost::asio::async_read(
socket_,
boost::asio::buffer(read_msg_.data(), chat_message::header_length),
[this](boost::system::error_code ec, std::size_t /*length*/) {
if (!ec && read_msg_.decode_header()) {
do_read_body();
} else {
socket_.close();
}
});
}
void do_read_body() {
boost::asio::async_read(
socket_, boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
[this](boost::system::error_code ec, std::size_t /*length*/) {
if (!ec) {
std::cout.write(read_msg_.body(), read_msg_.body_length());
std::cout << "\n";
do_read_header();
} else {
socket_.close();
}
});
}
void do_write() {
boost::asio::async_write(
socket_,
boost::asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
[this](boost::system::error_code ec, std::size_t /*length*/) {
if (!ec) {
write_msgs_.pop_front();
if (!write_msgs_.empty()) {
do_write();
}
} else {
socket_.close();
}
});
}
private:
boost::asio::io_context& io_context_;
tcp::socket socket_;
chat_message read_msg_;
chat_message_queue write_msgs_;
};
int main(int argc, char* argv[]) {
try {
if (argc != 3) {
std::cerr << "Usage: chat_client <host> <port>\n";
return 1;
}
boost::asio::io_context io_context;
tcp::resolver resolver(io_context);
auto endpoints = resolver.resolve(argv[1], argv[2]);
chat_client c(io_context, endpoints);
std::thread t([&io_context]() { io_context.run(); });
char line[chat_message::max_body_length + 1];
while (std::cin.getline(line, chat_message::max_body_length + 1)) {
chat_message msg;
msg.body_length(std::strlen(line));
std::memcpy(msg.body(), line, msg.body_length());
msg.encode_header();
c.write(msg);
}
c.close();
t.join();
} catch (std::exception& e) {
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}