-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconnectingClient.cpp
More file actions
130 lines (107 loc) · 5.38 KB
/
Copy pathconnectingClient.cpp
File metadata and controls
130 lines (107 loc) · 5.38 KB
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
130
#include <deque>
#include <array>
#include <thread>
#include <iostream>
#include <cstring>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <chrono>
#include "protocol.hpp"
// #define ASIO_STANDALONE // Still demands boost support?? Not going to bother figuring it out
using boost::asio::ip::tcp; // Standalone ASIO doesn't have TCP for some reason DESPITE being nested
class client {
public:
// Constructor
client(const std::array<char, MAX_NICKNAME>& username, boost::asio::ioServiceHandler& ioServiceHandler, tcp::resolver::iterator tcpEndpoint) :
asioService(ioServiceHandler), socketCon(ioServiceHandler) {
strcpy(nickName.data(), username.data());
memset(msgReader.data(), '\0', MAX_IP_PACK_SIZE); // Read ASCAIZ (Null Terminated String)
boost::asio::async_connect(socketCon, tcpEndpoint, boost::bind(&client::onConnect, this, _1));
// Starts the async connection on buffer, works like Producer - Consumer problem.
// On the Socket, to the tcpEndpoint, bind 'this' client to the server.
}
void write(const std::array<char, MAX_IP_PACK_SIZE>& msg) { // Call Write Handler
asioService.post(boost::bind(&client::writeImplement, this, msg));
}
void close() {
asioService.post(boost::bind(&client::closeImplement, this)); // Call Close Handler
}
private:
void onConnect(const boost::system::error_code& error) {
if (!error) { // On success, write to Nickname Buffer on Socket
boost::asio::async_write(socketCon,
boost::asio::buffer(nickName, nickName.size()),
boost::bind(&client::readHandler, this, _1));
}
}
void readHandler(const boost::system::error_code& error) {
std::cout << msgReader.data() << std::endl;
if (!error) { // On success, read from Nickname Buffer on Socket
boost::asio::async_read(socketCon,
boost::asio::buffer(msgReader, msgReader.size()),
boost::bind(&client::readHandler, this, _1));
} else {
closeImplement();
}
}
void writeHandler(const boost::system::error_code& error) {
if (!error) {
msgWriter.pop_front(); // Complete Unit Work
if (!msgWriter.empty()) { // Write remaining data
boost::asio::async_write(socketCon,
boost::asio::buffer(msgWriter.front(), msgWriter.front().size()),
boost::bind(&client::writeHandler, this, _1));
}
} else {
closeImplement(); // Data Written, close writer
}
void writeImplement(std::array<char, MAX_IP_PACK_SIZE> msg) {
msgWriter.push_back(msg); // Add to Writing Queue
if (msgWriter.empty()) { // Writing in progress
boost::asio::async_write(socketCon,
boost::asio::buffer(msgWriter.front(), msgWriter.front().size()),
boost::bind(&client::writeHandler, this, _1));
}
}
void closeImplement() {
socketCon.close(); // Close Handler and Connection
}
boost::asio::ioServiceHandler& asioService; // Asynch IO Service Client
tcp::socket socketCon; // TCP Socket for Connection
std::array<char, MAX_IP_PACK_SIZE> msgReader; // Size of Message Defined in protocol against buffer overflow for reader-writer
std::deque<std::array<char, MAX_IP_PACK_SIZE>> msgWriter;
std::array<char, MAX_NICKNAME> nickName; // Small array/string for name
};
int main(int argc, char* argv[]){
try {
if (argc != 4) {
std::cerr << "Usage: client <username> <host> <port>\n";
return 1;
}
// Must connect to host with username over a port
// Each port identifies different "chatroom", each isolated
// The isolation ensures isolation of transfer data to each "room"
boost::asio::ioServiceHandler ioServiceHandler; // IO service handler
tcp::resolver resolver(ioServiceHandler); // Scope and reference resolver
tcp::resolver::query query(argv[2], argv[3]); // TCP host connection on host:port
tcp::resolver::iterator iterator = resolver.resolve(query); // Resolve connection
std::array<char, MAX_NICKNAME> username; // Store nickname
strcpy(username.data(), argv[1]);
client cli(username, ioServiceHandler, iterator); // Start and link client
// Start concurrent thread for client
std::thread t(boost::bind(&boost::asio::ioServiceHandler::run, &ioServiceHandler));
std::array<char, MAX_IP_PACK_SIZE> msg;
while(1) {
memset(msg.data(), '\0', msg.size()); // Set memory buffer to NULL
if (!std::cin.getline(msg.data(), MAX_IP_PACK_SIZE - PADDING - MAX_NICKNAME)) {
std::cin.clear(); // Fetch memory after padding and clear system IO buffer
}
cli.write(msg); // Write fetched message
}
cli.close(); // Close client connection
t.join(); // And join thread to main stream
} catch (std::exception& e){
std::cerr << "Exception: " << e.what() << "\n"; // DEBUG
}
return 0;
}