diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..8157ad7
Binary files /dev/null and b/.DS_Store differ
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..73f69e0
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..583af74
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+Project_1
\ No newline at end of file
diff --git a/.idea/ClientServerProject.iml b/.idea/ClientServerProject.iml
new file mode 100644
index 0000000..f08604b
--- /dev/null
+++ b/.idea/ClientServerProject.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..578add8
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..79b3c94
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..e02efb8
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e8ede7c..e38faed 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,4 +3,4 @@ project(Project_1)
set(CMAKE_CXX_STANDARD 17)
-add_executable(Project_1 main.cpp sockets.cpp switch_expression.h)
\ No newline at end of file
+add_executable(Project_1 main.cpp sockets.cpp switch_expression.h helpers/terminal.h)
\ No newline at end of file
diff --git a/cmake-build-debug/Project_1 b/cmake-build-debug/Project_1
index be1f747..7188664 100755
Binary files a/cmake-build-debug/Project_1 and b/cmake-build-debug/Project_1 differ
diff --git a/cmake-build-debug/Project_1.cbp b/cmake-build-debug/Project_1.cbp
index 27468ca..a251cc8 100644
--- a/cmake-build-debug/Project_1.cbp
+++ b/cmake-build-debug/Project_1.cbp
@@ -8,89 +8,94 @@
-
+
-
-
-
-
+
+
+
+
-
+
-
-
-
-
+
+
+
+
-
+
-
-
-
-
+
+
+
+
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
+
-
-
-
-
+
+
+
+
-
+
-
+
-
+
-
+
-
+
+
+
+
diff --git a/helpers/terminal.h b/helpers/terminal.h
new file mode 100644
index 0000000..220b9c1
--- /dev/null
+++ b/helpers/terminal.h
@@ -0,0 +1,16 @@
+#pragma once
+
+inline auto terminal_size()
+{
+ struct winsize result{};
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &result);
+ return std::make_tuple(result.ws_col, result.ws_row);
+}
+
+template
+std::basic_ostream& hl( std::basic_ostream& os)
+{
+ auto [width, height] = terminal_size();
+ os << std::setfill('-') << std::setw(width) << "\n" << std::setfill(' ') << std::setw(0);
+ return os;
+}
diff --git a/main.cpp b/main.cpp
index 05385c1..2cfb790 100644
--- a/main.cpp
+++ b/main.cpp
@@ -4,10 +4,12 @@
#include "sockets.h"
#include "user_input.h"
#include
+#include
#include "server.h"
#include "osyncstream.h"
#include "switch_expression.h"
-
+#include
+#include "helpers/terminal.h"
/*
*
auto server(const addrinfo_up& address) noexcept -> void
@@ -92,7 +94,7 @@ auto client(const addrinfo_up& address) noexcept -> void
*
*/
-bool onClientConnected(networked& client)
+auto onClientConnected(networked& client)
{
sscout << "Accepted Client on Server.\n";
@@ -104,55 +106,103 @@ bool onClientConnected(networked& client)
}
auto onClientMessaged(networked& client, std::string& message)
{
- sscout << "message was " << message << "\n";
-
- client.send_message("thanks for the message!");
+ try
+ {
+ int operation = std::stoi(message);
+ sscout << "OPCode is " << operation << ".\n";
+ client.send_message("thanks for the message!");
+ }catch(std::invalid_argument& invalid_number)
+ {
+ sscout << "Invalid OPCode, Ignored.\n";
+ }
client.disconnect();
return true;
}
-inline auto resolve_selection(const int selection) -> std::string
+auto get_ip_port(int mode)
{
- if (selection == 1)
- return "Server";
- else if (selection == 2)
- return "Client";
- return "";
+ std::string ipaddress{};
+ std::uint16_t port{};
+ if (mode == 1)
+ ipaddress = "0.0.0.0";
+ else
+ ipaddress = get_input("Enter IP: ");
+ port = get_input("Enter Port:");
+ return std::make_tuple(mode == 1 ? "Server" : mode == 2 ? "Client" : "Unknown", ipaddress, port);
}
+auto execute_as_client(std::string ipaddress, std::uint16_t port)
+{
+ auto num_clients = get_input("Enter number of clients. (1-25)", "Invalid Amount", math::is_between<0, 26>);
+ auto operation = get_input("Pick Command\n\t1. Date", "Invalid Selection", math::is_between<0, 2>);
+ auto internal_tracker = 0;
+ std::vector threads{};
+ threads.reserve(num_clients);
+ auto [width, _] = terminal_size();
+ for(int i = 0; i < num_clients; ++i)
+ {
+ threads.emplace_back(std::thread([&, i]()
+ {
+ client net_client{};
+ auto start = std::chrono::high_resolution_clock::now();
+ net_client.message_received += [=, &internal_tracker](std::string& message)
+ {
+ auto end = std::chrono::high_resolution_clock::now();
+ std::chrono::duration elapsed = end-start;
+ sscout << "message for " << internal_tracker << math::numerical_suffix(internal_tracker++) << " of which is " << message << ".\n"
+ << "Round Trip Was " << elapsed.count() << " ms\n"
+ << hl;
+
+ return true;
+ };
+ auto res = net_client.connect(ipaddress, port);
+ if (res.joinable())
+ {
+ net_client.send_message(std::to_string(operation));
+ res.join();
+ }
+ }));
+ }
+ sscout << "All clients connected.\n";
+ for(auto&& thread : threads)
+ thread.join();
+ sscout << "Finished!\n";
+}
+
+
int main()
{
net::prologue();
const auto mode = get_input("Select Mode\n\t1. Server\n\t2. Client\n>:","Invalid Choice!",math::is_between<0,3>);
while (true)
{
- std::string ipaddress{};
- std::uint16_t port{};
- if (mode == 1)
- ipaddress = "0.0.0.0";
- else
- ipaddress = get_input("Enter IP: ");
- port = get_input("Enter Port:");
- sscout << resolve_selection(mode) << " selected, ip/port is " << ipaddress << "/" << port << ".\n";
- if (mode == 2)
- {
- client net_client{};
- net_client.message_received += [](std::string& what){
- sscout << "GOT " << what << ".\n";
- return true;
- };
- if(net_client.connect(ipaddress, port))
- {
- net_client.send_message("!Hello!\n");
- net_client.send_message("Second Message\n");
- net_client.send_message("Final Message!\n");
- while(net_client.is_valid()){}
+ auto [prefix, ipaddress, port] = get_ip_port(mode);
+ sscout << prefix << " selected, ip/port is " << ipaddress << "/" << port << ".\n";
+ if (mode == 2) {
+ execute_as_client(ipaddress, port);
+ continue;
+ for (int i = 0; i < 10; ++i) {
+ client net_client{};
+ net_client.message_received += [](std::string &what) {
+ sscout << "GOT " << what << ".\n";
+ return true;
+ };
+ auto res = net_client.connect(ipaddress, port);
+ if (res.joinable()) {
+ net_client.send_message(std::string("!Hello! from") + std::to_string(i) + "\n");
+ res.join();
+ } else {
+ sscout << "NO NET\n";
+ }
+ net_client.disconnect();
}
- else
- {
- sscout << "NO NET\n";
- }
- net_client.disconnect();
+ }
+ else{
+ server net_server{};
+
+ net_server.client_connected += onClientConnected;
+ net_server.message_received += onClientMessaged;
+ net_server.listen(ipaddress, port).join();
}
}
diff --git a/server.h b/server.h
index 0fda599..f5e3158 100755
--- a/server.h
+++ b/server.h
@@ -33,9 +33,8 @@ class client : public networked
while(is_valid()) /* Accept all messages */
{
auto message = receive_message();
- if (message.empty() && is_valid())
+ if (message.empty() && is_valid()) //connection is closed or broken.
{
- sscout << "Server Connection Lost\n";
disconnect();
break;
}
@@ -45,14 +44,14 @@ class client : public networked
public:
event message_received {};
explicit client() : networked(net::socket(AF_INET, SOCK_STREAM, 0)){}
- auto connect(const std::string& ip, const port port) -> bool
+ auto connect(const std::string& ip, const port port) -> std::thread
{
const auto address = net::getaddrinfo(ip, std::to_string(port));
auto remote_address = net::getaddrinfo(ip, std::to_string(port));
if (net::connect(socket, remote_address) < 0)
- return false;
- std::thread(&client::accept_message, this).detach();
- return true;
+ return std::thread();
+ auto thread = std::thread(&client::accept_message, this);
+ return thread;
}
};
@@ -74,8 +73,8 @@ class server : networked
auto accept_client_message(networked client) -> void //add const later
{
- using namespace std::chrono_literals;
- std::this_thread::sleep_for(2000ms);
+ //using namespace std::chrono_literals;
+ //std::this_thread::sleep_for(2000ms);
while(client.is_valid()) /* Accept all messages */
{
auto message = client.receive_message();
diff --git a/user_input.h b/user_input.h
index c32b685..a4c7b1c 100755
--- a/user_input.h
+++ b/user_input.h
@@ -12,6 +12,22 @@ namespace math
{
template::value, bool> = true>
constexpr auto is_between(typeof(lb) x) -> bool { return (ub > x) && (x > lb); }
+ template::value, bool> = true>
+ constexpr auto is_larger(typeof(lb) x) -> bool { return (x > lb); }
+ template::value, bool> = true>
+ constexpr auto is_smaller(typeof(ub) x) -> bool { return (ub > x); }
+ template::value, bool> = true>
+ auto numerical_suffix(T value) -> std::string
+ {
+ std::string suffixes[4] = {"th", "st", "nd", "rd"};
+ value %= 100;
+ if (math::is_between<11,13>(value))
+ return "th";
+ value %= 10;
+ if (math::is_larger<3>(value))
+ return "th";
+ return suffixes[value % 4];
+ }
}
template
@@ -37,6 +53,6 @@ T get_input(const std::string& prompt, const std::string& on_error, std::functio
}
catch (std::exception&) { return user_input; } /* This should not happen ..... cin/cout are not configured to throw...*/
}
-
+struct always_true_validator { template bool operator()(T) const { return true; }};
template
-T get_input(const std::string& prompt) { return get_input(prompt, "", [](auto) {return true; }); }
\ No newline at end of file
+T get_input(const std::string& prompt) { return get_input(prompt, "", always_true_validator()); }
\ No newline at end of file