From a1192a14c6a52e8ab77e1c84e38b65aa5e250bec Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 27 May 2021 15:13:46 +0800 Subject: import(life): Add computer network experiment. --- works/life/computer-network-experiment/client.cpp | 66 +++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 works/life/computer-network-experiment/client.cpp (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp new file mode 100644 index 0000000..926ece6 --- /dev/null +++ b/works/life/computer-network-experiment/client.cpp @@ -0,0 +1,66 @@ +/** Created by crupest. + * This is the client program. + */ + +#include +#include +#include +#include + +#pragma comment(lib, "ws2_32.lib") + +const auto connect_address = "127.0.0.1"; // control connect address +const u_short port = 1234; // control connect port + +int main() { + WSADATA wsa_data; + + if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) // initialize wsa + { + std::cerr << "WSA start up error!\n"; + WSACleanup(); + return 1; + } + + int client_socket; + + if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + std::cerr << "Failed to create socket!\n"; + WSACleanup(); + return 1; + } + + sockaddr_in server_address; + + server_address.sin_family = AF_INET; + server_address.sin_port = htons(port); + server_address.sin_addr.s_addr = inet_addr(connect_address); + memset(&(server_address.sin_zero), 0, sizeof(server_address.sin_zero)); + + if (connect(client_socket, (sockaddr *)&server_address, sizeof(sockaddr)) == + SOCKET_ERROR) { + std::cerr << "Failed to connect!"; + WSACleanup(); + return 1; + } + + const int buffer_size = 100; + char * buffer = new char[buffer_size]; + + int received_number = recv(client_socket, buffer, buffer_size, 0); + + if (received_number == -1) { + std::cerr << "Failed to recv."; + WSACleanup(); + return 1; + } + + std::string s(buffer, received_number); + + std::cout << "Received message:\n" << s; + + closesocket(client_socket); + WSACleanup(); + + return 0; +} -- cgit v1.2.3 From fcd2304e04dd3fabdefce4293b1b76ad99f8ed73 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 6 Jun 2021 22:13:43 +0800 Subject: import(life): ... --- .../computer-network-experiment/CMakeLists.txt | 8 +++-- works/life/computer-network-experiment/Common.cpp | 15 ++++++++- works/life/computer-network-experiment/Common.h | 2 ++ works/life/computer-network-experiment/client.cpp | 38 +++++++--------------- works/life/computer-network-experiment/server.cpp | 16 ++++----- 5 files changed, 40 insertions(+), 39 deletions(-) (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/CMakeLists.txt b/works/life/computer-network-experiment/CMakeLists.txt index dc82736..4d4277c 100644 --- a/works/life/computer-network-experiment/CMakeLists.txt +++ b/works/life/computer-network-experiment/CMakeLists.txt @@ -10,10 +10,14 @@ set(CMAKE_CXX_STANDARD 17) find_package(fmt CONFIG REQUIRED) find_package(Microsoft.GSL CONFIG REQUIRED) add_library(base STATIC Common.cpp StringUtil.cpp Output.cpp) -target_link_libraries(base PUBLIC Microsoft.GSL::GSL fmt::fmt) +target_link_libraries(base PUBLIC Microsoft.GSL::GSL fmt::fmt Folly::folly) +if(WIN32) +target_link_libraries(base PUBLIC Ws2_32) +endif() add_executable(client client.cpp) +target_link_libraries(client PRIVATE base) add_executable(server server.cpp) find_package(folly CONFIG REQUIRED) -target_link_libraries(server PRIVATE base Folly::folly) +target_link_libraries(server PRIVATE base) diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp index 02ac550..2e01dcb 100644 --- a/works/life/computer-network-experiment/Common.cpp +++ b/works/life/computer-network-experiment/Common.cpp @@ -5,7 +5,6 @@ #ifdef WIN32 #include #include -#pragma comment(lib, "Ws2_32.lib") #endif [[noreturn]] void PrintErrorMessageAndExit(StringView message, @@ -46,3 +45,17 @@ void InitWSA() { } } #endif + +int main() { +#ifdef WIN32 + InitWSA(); +#endif + + int c = Main(); + +#ifdef WIN32 + WSACleanup(); +#endif + + return c; +} diff --git a/works/life/computer-network-experiment/Common.h b/works/life/computer-network-experiment/Common.h index 1f4fa23..45a7da1 100644 --- a/works/life/computer-network-experiment/Common.h +++ b/works/life/computer-network-experiment/Common.h @@ -14,6 +14,8 @@ inline auto &output_stream = std::wcout; inline auto &error_stream = std::wcerr; #define CRUT(string_literal) L##string_literal +int Main(); + inline String ConvertCharString(std::string_view s) { return cru::ToUtf16WString(s); } diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index 926ece6..aeb352f 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -2,32 +2,22 @@ * This is the client program. */ +#include "Common.h" +#include "Output.h" + +#ifdef WIN32 #include -#include -#include #include - -#pragma comment(lib, "ws2_32.lib") +#endif const auto connect_address = "127.0.0.1"; // control connect address const u_short port = 1234; // control connect port -int main() { - WSADATA wsa_data; - - if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) // initialize wsa - { - std::cerr << "WSA start up error!\n"; - WSACleanup(); - return 1; - } - +int Main() { int client_socket; if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - std::cerr << "Failed to create socket!\n"; - WSACleanup(); - return 1; + PrintErrorMessageAndExit(CRUT("Failed to create socket!\n")); } sockaddr_in server_address; @@ -39,28 +29,22 @@ int main() { if (connect(client_socket, (sockaddr *)&server_address, sizeof(sockaddr)) == SOCKET_ERROR) { - std::cerr << "Failed to connect!"; - WSACleanup(); - return 1; + PrintErrorMessageAndExit(CRUT("Failed to connect!")); } const int buffer_size = 100; - char * buffer = new char[buffer_size]; + char *buffer = new char[buffer_size]; int received_number = recv(client_socket, buffer, buffer_size, 0); if (received_number == -1) { - std::cerr << "Failed to recv."; - WSACleanup(); - return 1; + PrintErrorMessageAndExit(CRUT("Failed to recv.")); } std::string s(buffer, received_number); - std::cout << "Received message:\n" << s; + SendOutput(CRUT("Received message:\n")); closesocket(client_socket); - WSACleanup(); - return 0; } diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index 297114b..9cf655a 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -2,15 +2,17 @@ * This is the server program. */ +#include "Common.h" #include "Output.h" -#include -#include #include -#include -#include #include +#ifdef WIN32 +#include +#include +#endif + const auto bind_address = "127.0.0.1"; // control bind address const u_short port = 1234; // control bind port @@ -48,11 +50,7 @@ void ResponseThreadProc(int socket, sockaddr_in address) { closesocket(socket); } -int main() { -#ifdef WIN32 - InitWSA(); -#endif - +int Main() { int server_socket; if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { -- cgit v1.2.3 From 7a269e185fc59e5f81e7c91e6e75891ba2ca4b3b Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 6 Jun 2021 23:43:52 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/Common.cpp | 13 +++++++++++++ works/life/computer-network-experiment/Common.h | 8 +++++--- works/life/computer-network-experiment/client.cpp | 11 ++++++++--- works/life/computer-network-experiment/server.cpp | 23 ++++++++++++++--------- 4 files changed, 40 insertions(+), 15 deletions(-) (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp index 2e01dcb..59c2f0f 100644 --- a/works/life/computer-network-experiment/Common.cpp +++ b/works/life/computer-network-experiment/Common.cpp @@ -5,6 +5,11 @@ #ifdef WIN32 #include #include +#else +#include +#include +#include +#include #endif [[noreturn]] void PrintErrorMessageAndExit(StringView message, @@ -46,6 +51,14 @@ void InitWSA() { } #endif +int Close(int socket) { +#ifdef WIN32 + return closesocket(socket); +#else + return close(socket); +#endif +} + int main() { #ifdef WIN32 InitWSA(); diff --git a/works/life/computer-network-experiment/Common.h b/works/life/computer-network-experiment/Common.h index 45a7da1..4e30439 100644 --- a/works/life/computer-network-experiment/Common.h +++ b/works/life/computer-network-experiment/Common.h @@ -14,8 +14,6 @@ inline auto &output_stream = std::wcout; inline auto &error_stream = std::wcerr; #define CRUT(string_literal) L##string_literal -int Main(); - inline String ConvertCharString(std::string_view s) { return cru::ToUtf16WString(s); } @@ -28,12 +26,16 @@ inline auto &output_stream = std::cout; inline auto &error_stream = std::cerr; #define CRUT(string_literal) string_literal -inline String ConvertCharString(std::string_view s) { return s; } +inline String ConvertCharString(std::string_view s) { return String(s); } #endif +int Main(); + [[noreturn]] void PrintErrorMessageAndExit(StringView message, bool print_last_error = true); #ifdef WIN32 void InitWSA(); #endif + +int Close(int socket); diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index aeb352f..f209171 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -8,6 +8,11 @@ #ifdef WIN32 #include #include +#else +#include +#include +#include + #endif const auto connect_address = "127.0.0.1"; // control connect address @@ -16,7 +21,7 @@ const u_short port = 1234; // control connect port int Main() { int client_socket; - if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { PrintErrorMessageAndExit(CRUT("Failed to create socket!\n")); } @@ -28,7 +33,7 @@ int Main() { memset(&(server_address.sin_zero), 0, sizeof(server_address.sin_zero)); if (connect(client_socket, (sockaddr *)&server_address, sizeof(sockaddr)) == - SOCKET_ERROR) { + -1) { PrintErrorMessageAndExit(CRUT("Failed to connect!")); } @@ -45,6 +50,6 @@ int Main() { SendOutput(CRUT("Received message:\n")); - closesocket(client_socket); + Close(client_socket); return 0; } diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index 9cf655a..ff03783 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -11,6 +11,11 @@ #ifdef WIN32 #include #include +#else +#include +#include +#include + #endif const auto bind_address = "127.0.0.1"; // control bind address @@ -35,9 +40,9 @@ void ResponseThreadProc(int socket, sockaddr_in address) { buffer.size() - byte_count_sent, 0); // send failed - if (byte_actually_sent == SOCKET_ERROR) { - std::cerr << "Failed to send!\n"; - closesocket(socket); + if (byte_actually_sent == -1) { + SendOutput(OutputType::Error, CRUT("Failed to send!\n")); + Close(socket); break; } @@ -47,13 +52,13 @@ void ResponseThreadProc(int socket, sockaddr_in address) { SendOutput(CRUT("Succeeded to send message to {} !\n"), ConvertCharString(address_string)); - closesocket(socket); + Close(socket); } int Main() { int server_socket; - if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { PrintErrorMessageAndExit(CRUT("Failed to create socket.")); } @@ -65,23 +70,23 @@ int Main() { memset(&(server_address.sin_zero), 0, sizeof(server_address.sin_zero)); if (bind(server_socket, reinterpret_cast(&server_address), - sizeof(sockaddr_in)) == SOCKET_ERROR) { + sizeof(sockaddr_in)) == -1) { PrintErrorMessageAndExit(CRUT("Failed to bind.")); } - if (listen(server_socket, SOMAXCONN) == SOCKET_ERROR) { + if (listen(server_socket, SOMAXCONN) == -1) { PrintErrorMessageAndExit(CRUT("Failed to listen.")); } while (true) { sockaddr_in client_address; int client_socket; - int sin_size = sizeof(sockaddr_in); + unsigned sin_size = sizeof(sockaddr_in); client_socket = accept(server_socket, reinterpret_cast(&client_address), &sin_size); - if (client_socket == INVALID_SOCKET) { + if (client_socket == -1) { PrintErrorMessageAndExit(CRUT("Failed to accecpt")); } -- cgit v1.2.3 From da6c0e6194578538ce0bcd1b9815696b96153f6b Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 7 Jun 2021 14:05:51 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/Common.cpp | 19 +++++----- works/life/computer-network-experiment/Common.h | 4 ++- works/life/computer-network-experiment/Output.cpp | 43 ++++++++++++++++++----- works/life/computer-network-experiment/Output.h | 6 ++++ works/life/computer-network-experiment/client.cpp | 4 +-- works/life/computer-network-experiment/server.cpp | 12 +++---- 6 files changed, 62 insertions(+), 26 deletions(-) (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp index 59c2f0f..fbdb2c8 100644 --- a/works/life/computer-network-experiment/Common.cpp +++ b/works/life/computer-network-experiment/Common.cpp @@ -34,9 +34,7 @@ #endif } -#ifdef WIN32 - WSACleanup(); -#endif + BeforeExit(); std::exit(1); } @@ -51,7 +49,7 @@ void InitWSA() { } #endif -int Close(int socket) { +int CloseSocket(int socket) { #ifdef WIN32 return closesocket(socket); #else @@ -59,16 +57,21 @@ int Close(int socket) { #endif } -int main() { +void BeforeExit() { #ifdef WIN32 - InitWSA(); + WSACleanup(); #endif - int c = Main(); + SignalAndWaitForOutputThreadStop(); +} +int main() { #ifdef WIN32 - WSACleanup(); + InitWSA(); #endif + int c = Main(); + + BeforeExit(); return c; } diff --git a/works/life/computer-network-experiment/Common.h b/works/life/computer-network-experiment/Common.h index 4e30439..e5612fd 100644 --- a/works/life/computer-network-experiment/Common.h +++ b/works/life/computer-network-experiment/Common.h @@ -38,4 +38,6 @@ int Main(); void InitWSA(); #endif -int Close(int socket); +int CloseSocket(int socket); + +void BeforeExit(); diff --git a/works/life/computer-network-experiment/Output.cpp b/works/life/computer-network-experiment/Output.cpp index 2968c19..8efb525 100644 --- a/works/life/computer-network-experiment/Output.cpp +++ b/works/life/computer-network-experiment/Output.cpp @@ -1,18 +1,43 @@ #include "Output.h" +#include "folly/CancellationToken.h" folly::MPMCQueue output_queue(100); +folly::CancellationSource cancellation_source; + +std::thread output_thread(OutputThread); + +void PrintOutput(const Output &output) { + switch (output.type) { + case OutputType::Error: + error_stream << output.message; + break; + default: + output_stream << output.message; + break; + } +} + void OutputThread() { while (true) { - Output output; - output_queue.blockingRead(output); - switch (output.type) { - case OutputType::Error: - error_stream << output.message; - break; - default: - output_stream << output.message; - break; + if (cancellation_source.getToken().isCancellationRequested()) { + while (true) { + Output output; + if (output_queue.readIfNotEmpty(output)) { + PrintOutput(output); + } else { + return; + } + } } + + Output output; + if (output_queue.readIfNotEmpty(output)) + PrintOutput(output); } } + +void SignalAndWaitForOutputThreadStop() { + cancellation_source.requestCancellation(); + output_thread.join(); +} diff --git a/works/life/computer-network-experiment/Output.h b/works/life/computer-network-experiment/Output.h index b81dbfd..22b913a 100644 --- a/works/life/computer-network-experiment/Output.h +++ b/works/life/computer-network-experiment/Output.h @@ -5,7 +5,9 @@ #include #include #include +#include +#include #include enum class OutputType { Normal, Error }; @@ -42,3 +44,7 @@ void SendOutput(OutputType type, StringView format, Args &&...args) { } void OutputThread(); + +void SignalAndWaitForOutputThreadStop(); + +extern std::thread output_thread; diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index f209171..5d5075e 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -48,8 +48,8 @@ int Main() { std::string s(buffer, received_number); - SendOutput(CRUT("Received message:\n")); + SendOutput(CRUT("Received message:\n{}\n"), ConvertCharString(s)); - Close(client_socket); + CloseSocket(client_socket); return 0; } diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index a5a7a9b..14987f3 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -42,22 +42,20 @@ void ResponseThreadProc(int socket, sockaddr_in address) { // send failed if (byte_actually_sent == -1) { SendOutput(OutputType::Error, CRUT("Failed to send!\n")); - Close(socket); + CloseSocket(socket); break; } byte_count_sent += byte_actually_sent; } - SendOutput(CRUT("Succeeded to send message to {} !\n"), + SendOutput(CRUT("Succeeded to send message to {}!\n"), ConvertCharString(address_string)); - Close(socket); + CloseSocket(socket); } int Main() { - std::thread output_thread(OutputThread); - int server_socket; if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { @@ -81,6 +79,8 @@ int Main() { } while (true) { + SendOutput(CRUT("Now start to accept incoming connection.\n")); + sockaddr_in client_address; int client_socket; unsigned sin_size = sizeof(sockaddr_in); @@ -92,7 +92,7 @@ int Main() { (&sin_size)); if (client_socket == -1) { - PrintErrorMessageAndExit(CRUT("Failed to accecpt")); + PrintErrorMessageAndExit(CRUT("Failed to accecpt.")); } std::thread response_thread(ResponseThreadProc, client_socket, -- cgit v1.2.3 From 868936626cd32590b697cc5ba0c67e032deabd38 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 7 Jun 2021 19:24:39 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/Output.cpp | 27 ++++++++++++++++++++--- works/life/computer-network-experiment/Output.h | 22 +++++++++++++++--- works/life/computer-network-experiment/client.cpp | 3 ++- works/life/computer-network-experiment/server.cpp | 7 +++--- 4 files changed, 49 insertions(+), 10 deletions(-) (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/Output.cpp b/works/life/computer-network-experiment/Output.cpp index 8efb525..e3dc69e 100644 --- a/works/life/computer-network-experiment/Output.cpp +++ b/works/life/computer-network-experiment/Output.cpp @@ -1,5 +1,9 @@ #include "Output.h" -#include "folly/CancellationToken.h" + +#include + +#include +#include folly::MPMCQueue output_queue(100); @@ -8,12 +12,29 @@ folly::CancellationSource cancellation_source; std::thread output_thread(OutputThread); void PrintOutput(const Output &output) { + std::basic_ostream *stream; + switch (output.type) { case OutputType::Error: - error_stream << output.message; + stream = &error_stream; break; default: - output_stream << output.message; + stream = &output_stream; + break; + } + + switch (output.color) { + case OutputColor::Normal: + (*stream) << output.message; + break; + case OutputColor::Green: + (*stream) << CRUT("\x1b[32m") << output.message << CRUT("\x1b[0m"); + break; + case OutputColor::Red: + (*stream) << CRUT("\x1b[31m") << output.message << CRUT("\x1b[0m"); + break; + case OutputColor::Yellow: + (*stream) << CRUT("\x1b[33m") << output.message << CRUT("\x1b[0m"); break; } } diff --git a/works/life/computer-network-experiment/Output.h b/works/life/computer-network-experiment/Output.h index 22b913a..2d16eb0 100644 --- a/works/life/computer-network-experiment/Output.h +++ b/works/life/computer-network-experiment/Output.h @@ -3,19 +3,28 @@ #include "StringUtil.hpp" #include +#include #include #include -#include -#include #include +#include enum class OutputType { Normal, Error }; +enum class OutputColor { Normal, Green, Red, Yellow }; struct Output { Output() = default; Output(String message, OutputType type = OutputType::Normal) - : message(std::move(message)), type(type) {} + : message(std::move(message)), type(type), + color(type == OutputType::Error ? OutputColor::Red + : OutputColor::Normal) {} + + Output(String message, OutputColor color) + : message(std::move(message)), type(OutputType::Normal), color(color) {} + + Output(String message, OutputType type, OutputColor color) + : message(std::move(message)), type(type), color(color) {} CRU_DEFAULT_COPY(Output) CRU_DEFAULT_MOVE(Output) @@ -23,6 +32,7 @@ struct Output { String message; OutputType type; + OutputColor color; }; extern folly::MPMCQueue output_queue; @@ -43,6 +53,12 @@ void SendOutput(OutputType type, StringView format, Args &&...args) { Output{fmt::format(format, std::forward(args)...), type}); } +template +void SendOutput(OutputColor color, StringView format, Args &&...args) { + output_queue.blockingWrite( + Output{fmt::format(format, std::forward(args)...), color}); +} + void OutputThread(); void SignalAndWaitForOutputThreadStop(); diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index 5d5075e..922ecdc 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -48,7 +48,8 @@ int Main() { std::string s(buffer, received_number); - SendOutput(CRUT("Received message:\n{}\n"), ConvertCharString(s)); + SendOutput(OutputColor::Green, CRUT("Received message:\n")); + SendOutput(OutputColor::Normal, CRUT("{}\n"), ConvertCharString(s)); CloseSocket(client_socket); return 0; diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index 14987f3..f12630a 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -49,7 +49,7 @@ void ResponseThreadProc(int socket, sockaddr_in address) { byte_count_sent += byte_actually_sent; } - SendOutput(CRUT("Succeeded to send message to {}!\n"), + SendOutput(OutputColor::Green, CRUT("Succeeded to send message to {}!\n"), ConvertCharString(address_string)); CloseSocket(socket); @@ -78,9 +78,10 @@ int Main() { PrintErrorMessageAndExit(CRUT("Failed to listen.")); } - while (true) { - SendOutput(CRUT("Now start to accept incoming connection.\n")); + SendOutput(OutputColor::Green, + CRUT("Now start to accept incoming connection.\n")); + while (true) { sockaddr_in client_address; int client_socket; unsigned sin_size = sizeof(sockaddr_in); -- cgit v1.2.3 From c10e08c3896343cc7ddffe1dd7b1d09da2f8548e Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 7 Jun 2021 20:20:10 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/Common.cpp | 70 +++++++++++++++++++++++ works/life/computer-network-experiment/Common.h | 5 ++ works/life/computer-network-experiment/Output.cpp | 11 ++++ works/life/computer-network-experiment/Output.h | 3 +- works/life/computer-network-experiment/client.cpp | 19 +++--- works/life/computer-network-experiment/server.cpp | 29 ++-------- 6 files changed, 100 insertions(+), 37 deletions(-) (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp index 5be3971..22f8b63 100644 --- a/works/life/computer-network-experiment/Common.cpp +++ b/works/life/computer-network-experiment/Common.cpp @@ -12,6 +12,8 @@ #include #endif +#include + [[noreturn]] void PrintErrorMessageAndExit(StringView message, bool print_last_error) { @@ -40,6 +42,7 @@ } #ifdef WIN32 +namespace { void InitWSA() { WSADATA wsa_data; @@ -47,6 +50,8 @@ void InitWSA() { PrintErrorMessageAndExit(CRUT("Failed to initialize wsa.")); } } +} // namespace + #endif int CloseSocket(int socket) { @@ -65,6 +70,71 @@ void BeforeExit() { SignalAndWaitForOutputThreadStop(); } +String ReadInputLine() { + String line; + std::getline(input_stream, line); + return line; +} + +void SafeSend(int socket, std::string_view buffer) { + const int total_byte_count = buffer.size(); + int byte_count_sent = 0; + int retry_count = 0; + + while (true) { + // Now we have sent all data. + if (byte_count_sent == total_byte_count) + break; + + auto byte_actually_sent = send(socket, buffer.data() + byte_count_sent, + buffer.size() - byte_count_sent, 0); + + // send failed + if (byte_actually_sent == -1) { + SendOutput(OutputType::Error, CRUT("Failed to send!\n")); + CloseSocket(socket); + break; + } + + byte_count_sent += byte_actually_sent; + } +} + +std::string SafeReadUntil(int socket, char c, std::string &rest) { + std::string result = rest; + + const int buffer_size = 100; + char *buffer = new char[buffer_size]; + + while (true) { + int received_number = recv(socket, buffer, buffer_size, 0); + + if (received_number == -1) { + PrintErrorMessageAndExit(CRUT("Failed to recv.")); + } + + bool b = false; + + for (int i = 0; i < received_number; i++) { + if (buffer[i] == '\n') { + result.append(buffer, i); + rest = std::string(buffer + i + 1, received_number - i - 1); + b = true; + break; + } + } + + if (b) + break; + + result.append(buffer, received_number); + } + + delete[] buffer; + + return result; +} + int main() { #ifdef WIN32 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); diff --git a/works/life/computer-network-experiment/Common.h b/works/life/computer-network-experiment/Common.h index e5612fd..c3b6094 100644 --- a/works/life/computer-network-experiment/Common.h +++ b/works/life/computer-network-experiment/Common.h @@ -41,3 +41,8 @@ void InitWSA(); int CloseSocket(int socket); void BeforeExit(); + +String ReadInputLine(); + +void SafeSend(int socket, std::string_view buffer); +std::string SafeReadUntil(int socket, char c, std::string& rest); diff --git a/works/life/computer-network-experiment/Output.cpp b/works/life/computer-network-experiment/Output.cpp index 2989c98..db97e5e 100644 --- a/works/life/computer-network-experiment/Output.cpp +++ b/works/life/computer-network-experiment/Output.cpp @@ -2,9 +2,12 @@ #include +#include #include #include +std::mutex m; + folly::MPMCQueue output_queue(100); folly::CancellationSource cancellation_source; @@ -44,6 +47,8 @@ void PrintOutput(const Output &output) { void OutputThread() { while (true) { + m.lock(); + if (cancellation_source.getToken().isCancellationRequested()) { while (true) { Output output; @@ -58,6 +63,8 @@ void OutputThread() { Output output; if (output_queue.readIfNotEmpty(output)) PrintOutput(output); + + m.unlock(); } } @@ -65,3 +72,7 @@ void SignalAndWaitForOutputThreadStop() { cancellation_source.requestCancellation(); output_thread.join(); } + +std::lock_guard BlockOutputThread() { + return std::lock_guard(m); +} diff --git a/works/life/computer-network-experiment/Output.h b/works/life/computer-network-experiment/Output.h index 2d16eb0..689c3d3 100644 --- a/works/life/computer-network-experiment/Output.h +++ b/works/life/computer-network-experiment/Output.h @@ -8,6 +8,7 @@ #include #include +#include #include enum class OutputType { Normal, Error }; @@ -63,4 +64,4 @@ void OutputThread(); void SignalAndWaitForOutputThreadStop(); -extern std::thread output_thread; +std::lock_guard BlockOutputThread(); diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index 922ecdc..2494bae 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -37,19 +37,16 @@ int Main() { PrintErrorMessageAndExit(CRUT("Failed to connect!")); } - const int buffer_size = 100; - char *buffer = new char[buffer_size]; - - int received_number = recv(client_socket, buffer, buffer_size, 0); - - if (received_number == -1) { - PrintErrorMessageAndExit(CRUT("Failed to recv.")); + String name; + { + auto guard = BlockOutputThread(); + output_stream << CRUT("Please input your name:"); + name = ReadInputLine(); } - std::string s(buffer, received_number); - - SendOutput(OutputColor::Green, CRUT("Received message:\n")); - SendOutput(OutputColor::Normal, CRUT("{}\n"), ConvertCharString(s)); + String name_data = ConvertCharString(name); + SafeSend(client_socket, + std::string_view{name_data.data(), name_data.size() + 1}); CloseSocket(client_socket); return 0; diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index ac80125..2877c61 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -22,34 +22,13 @@ const u_short port = 1234; // control bind port void ResponseThreadProc(int socket, sockaddr_in address) { auto address_string = inet_ntoa(address.sin_addr); - SendOutput(CRUT("Connected to {}!\n"), ConvertCharString(address_string)); - const std::string_view buffer = "Love you!!! By crupest!"; + std::string rest; - const int total_byte_count = buffer.size(); - int byte_count_sent = 0; - int retry_count = 0; + std::string name = SafeReadUntil(socket, '\n', rest); - while (true) { - // Now we have sent all data. - if (byte_count_sent == total_byte_count) - break; - - auto byte_actually_sent = send(socket, buffer.data() + byte_count_sent, - buffer.size() - byte_count_sent, 0); - - // send failed - if (byte_actually_sent == -1) { - SendOutput(OutputType::Error, CRUT("Failed to send!\n")); - CloseSocket(socket); - break; - } - - byte_count_sent += byte_actually_sent; - } - - SendOutput(OutputColor::Green, CRUT("Succeeded to send message to {}!\n"), - ConvertCharString(address_string)); + SendOutput(CRUT("Connected to {}, whose name is {}."), + ConvertCharString(address_string), ConvertCharString(name)); CloseSocket(socket); } -- cgit v1.2.3 From 2bc323cfa5d317188da591413bce7f1230e383b4 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 7 Jun 2021 20:33:23 +0800 Subject: import(life): ... --- .../life/computer-network-experiment/.vscode/launch.json | 16 ++++++++++++++++ works/life/computer-network-experiment/Common.cpp | 2 +- works/life/computer-network-experiment/client.cpp | 4 ++-- 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 works/life/computer-network-experiment/.vscode/launch.json (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/.vscode/launch.json b/works/life/computer-network-experiment/.vscode/launch.json new file mode 100644 index 0000000..882a540 --- /dev/null +++ b/works/life/computer-network-experiment/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch server.", + "type": "gdb", + "request": "launch", + "target": "${workspaceRoot}/build/server", + "cwd": "${workspaceRoot}", + "valuesFormatting": "parseText" + } + ] +} \ No newline at end of file diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp index 22f8b63..e4615fc 100644 --- a/works/life/computer-network-experiment/Common.cpp +++ b/works/life/computer-network-experiment/Common.cpp @@ -116,7 +116,7 @@ std::string SafeReadUntil(int socket, char c, std::string &rest) { bool b = false; for (int i = 0; i < received_number; i++) { - if (buffer[i] == '\n') { + if (buffer[i] == c) { result.append(buffer, i); rest = std::string(buffer + i + 1, received_number - i - 1); b = true; diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index 2494bae..489948f 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -44,9 +44,9 @@ int Main() { name = ReadInputLine(); } + name.push_back(CRUT('\n')); String name_data = ConvertCharString(name); - SafeSend(client_socket, - std::string_view{name_data.data(), name_data.size() + 1}); + SafeSend(client_socket, name_data); CloseSocket(client_socket); return 0; -- cgit v1.2.3 From 42f7fc1876cbe68569771b97a8935fbca7fa3ee4 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 7 Jun 2021 20:42:28 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/Common.h | 11 +- works/life/computer-network-experiment/Output.cpp | 4 +- .../computer-network-experiment/StringUtil.cpp | 120 +++++++++++++-------- .../computer-network-experiment/StringUtil.hpp | 1 + works/life/computer-network-experiment/client.cpp | 2 +- 5 files changed, 84 insertions(+), 54 deletions(-) (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/Common.h b/works/life/computer-network-experiment/Common.h index c3b6094..6886e38 100644 --- a/works/life/computer-network-experiment/Common.h +++ b/works/life/computer-network-experiment/Common.h @@ -17,6 +17,10 @@ inline auto &error_stream = std::wcerr; inline String ConvertCharString(std::string_view s) { return cru::ToUtf16WString(s); } + +inline std::string ConvertCharStringBack(StringView s) { + return cru::ToUtf8(s); +} #else using Char = char; using String = std::string; @@ -27,6 +31,7 @@ inline auto &error_stream = std::cerr; #define CRUT(string_literal) string_literal inline String ConvertCharString(std::string_view s) { return String(s); } +inline std::string ConvertCharStringBack(StringView s) { return {s}; } #endif int Main(); @@ -34,10 +39,6 @@ int Main(); [[noreturn]] void PrintErrorMessageAndExit(StringView message, bool print_last_error = true); -#ifdef WIN32 -void InitWSA(); -#endif - int CloseSocket(int socket); void BeforeExit(); @@ -45,4 +46,4 @@ void BeforeExit(); String ReadInputLine(); void SafeSend(int socket, std::string_view buffer); -std::string SafeReadUntil(int socket, char c, std::string& rest); +std::string SafeReadUntil(int socket, char c, std::string &rest); diff --git a/works/life/computer-network-experiment/Output.cpp b/works/life/computer-network-experiment/Output.cpp index db97e5e..fbbd6ba 100644 --- a/works/life/computer-network-experiment/Output.cpp +++ b/works/life/computer-network-experiment/Output.cpp @@ -47,7 +47,7 @@ void PrintOutput(const Output &output) { void OutputThread() { while (true) { - m.lock(); + std::lock_guard guard(m); if (cancellation_source.getToken().isCancellationRequested()) { while (true) { @@ -63,8 +63,6 @@ void OutputThread() { Output output; if (output_queue.readIfNotEmpty(output)) PrintOutput(output); - - m.unlock(); } } diff --git a/works/life/computer-network-experiment/StringUtil.cpp b/works/life/computer-network-experiment/StringUtil.cpp index 1224bdc..6bf906d 100644 --- a/works/life/computer-network-experiment/StringUtil.cpp +++ b/works/life/computer-network-experiment/StringUtil.cpp @@ -5,14 +5,14 @@ namespace cru { namespace { template -inline std::enable_if_t, ReturnType> ExtractBits( - UInt n) { +inline std::enable_if_t, ReturnType> +ExtractBits(UInt n) { return static_cast(n & ((1u << number_of_bit) - 1)); } -} // namespace +} // namespace CodePoint Utf8NextCodePoint(std::string_view str, Index current, - Index* next_position) { + Index *next_position) { CodePoint result; if (current >= static_cast(str.length())) { @@ -37,9 +37,9 @@ CodePoint Utf8NextCodePoint(std::string_view str, Index current, }; if ((1u << 7) & cu0) { - if ((1u << 6) & cu0) { // 2~4-length code point - if ((1u << 5) & cu0) { // 3~4-length code point - if ((1u << 4) & cu0) { // 4-length code point + if ((1u << 6) & cu0) { // 2~4-length code point + if ((1u << 5) & cu0) { // 3~4-length code point + if ((1u << 4) & cu0) { // 4-length code point if (cu0 & (1u << 3)) { throw TextEncodeException( "Unexpected bad-format begin byte (not 0b11110xxx) of 4-byte" @@ -52,14 +52,14 @@ CodePoint Utf8NextCodePoint(std::string_view str, Index current, const CodePoint s2 = read_next_folowing_code() << 6; const CodePoint s3 = read_next_folowing_code(); result = s0 + s1 + s2 + s3; - } else { // 3-length code point + } else { // 3-length code point const CodePoint s0 = ExtractBits(cu0) << (6 * 2); const CodePoint s1 = read_next_folowing_code() << 6; const CodePoint s2 = read_next_folowing_code(); result = s0 + s1 + s2; } - } else { // 2-length code point + } else { // 2-length code point const CodePoint s0 = ExtractBits(cu0) << 6; const CodePoint s1 = read_next_folowing_code(); @@ -74,12 +74,13 @@ CodePoint Utf8NextCodePoint(std::string_view str, Index current, } } - if (next_position != nullptr) *next_position = current; + if (next_position != nullptr) + *next_position = current; return result; } CodePoint Utf16NextCodePoint(std::u16string_view str, Index current, - Index* next_position) { + Index *next_position) { CodePoint result; if (current >= static_cast(str.length())) { @@ -87,9 +88,9 @@ CodePoint Utf16NextCodePoint(std::u16string_view str, Index current, } else { const auto cu0 = str[current++]; - if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point + if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point result = static_cast(cu0); - } else if (IsUtf16SurrogatePairLeading(cu0)) { // 2-length code point + } else if (IsUtf16SurrogatePairLeading(cu0)) { // 2-length code point if (current >= static_cast(str.length())) { throw TextEncodeException( "Unexpected end when reading second code unit of surrogate pair."); @@ -112,21 +113,22 @@ CodePoint Utf16NextCodePoint(std::u16string_view str, Index current, } } - if (next_position != nullptr) *next_position = current; + if (next_position != nullptr) + *next_position = current; return result; } CodePoint Utf16PreviousCodePoint(std::u16string_view str, Index current, - Index* previous_position) { + Index *previous_position) { CodePoint result; if (current <= 0) { result = k_invalid_code_point; } else { const auto cu0 = str[--current]; - if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point + if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point result = static_cast(cu0); - } else if (IsUtf16SurrogatePairTrailing(cu0)) { // 2-length code point + } else if (IsUtf16SurrogatePairTrailing(cu0)) { // 2-length code point if (current <= 0) { throw TextEncodeException( "Unexpected end when reading first code unit of surrogate pair."); @@ -149,11 +151,12 @@ CodePoint Utf16PreviousCodePoint(std::u16string_view str, Index current, } } - if (previous_position != nullptr) *previous_position = current; + if (previous_position != nullptr) + *previous_position = current; return result; } -void Utf8EncodeCodePointAppend(CodePoint code_point, std::string& str) { +void Utf8EncodeCodePointAppend(CodePoint code_point, std::string &str) { auto write_continue_byte = [&str](std::uint8_t byte6) { str.push_back((1u << 7) + (((1u << 6) - 1) & byte6)); }; @@ -192,7 +195,7 @@ void Utf8EncodeCodePointAppend(CodePoint code_point, std::string& str) { } } -void Utf16EncodeCodePointAppend(CodePoint code_point, std::u16string& str) { +void Utf16EncodeCodePointAppend(CodePoint code_point, std::u16string &str) { if ((code_point >= 0 && code_point <= 0xD7FF) || (code_point >= 0xE000 && code_point <= 0xFFFF)) { str.push_back(static_cast(code_point)); @@ -224,6 +227,15 @@ std::u16string ToUtf16(std::string_view s) { } #ifdef WIN32 +std::string ToUtf8(std::wstring_view s) { + std::u16string_view string{reinterpret_cast(s.data()), + s.size()}; + std::string result; + for (CodePoint cp : Utf16CodePointIterator{string}) { + Utf8EncodeCodePointAppend(cp, result); + } + return result; +} std::wstring ToUtf16WString(std::string_view s) { std::u16string result; for (CodePoint cp : Utf8CodePointIterator{s}) { @@ -236,33 +248,43 @@ std::wstring ToUtf16WString(std::string_view s) { #endif bool Utf16IsValidInsertPosition(std::u16string_view s, gsl::index position) { - if (position < 0) return false; - if (position > static_cast(s.size())) return false; - if (position == 0) return true; - if (position == static_cast(s.size())) return true; + if (position < 0) + return false; + if (position > static_cast(s.size())) + return false; + if (position == 0) + return true; + if (position == static_cast(s.size())) + return true; return !IsUtf16SurrogatePairTrailing(s[position]); } gsl::index Utf16BackwardUntil(std::u16string_view str, gsl::index position, - const std::function& predicate) { - if (position <= 0) return position; + const std::function &predicate) { + if (position <= 0) + return position; while (true) { gsl::index p = position; auto c = Utf16PreviousCodePoint(str, p, &position); - if (predicate(c)) return p; - if (c == k_invalid_code_point) return p; + if (predicate(c)) + return p; + if (c == k_invalid_code_point) + return p; } UnreachableCode(); } gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position, - const std::function& predicate) { - if (position >= static_cast(str.size())) return position; + const std::function &predicate) { + if (position >= static_cast(str.size())) + return position; while (true) { gsl::index p = position; auto c = Utf16NextCodePoint(str, p, &position); - if (predicate(c)) return p; - if (c == k_invalid_code_point) return p; + if (predicate(c)) + return p; + if (c == k_invalid_code_point) + return p; } UnreachableCode(); } @@ -270,29 +292,35 @@ gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position, inline bool IsSpace(CodePoint c) { return c == 0x20 || c == 0xA; } gsl::index Utf16PreviousWord(std::u16string_view str, gsl::index position, - bool* is_space) { - if (position <= 0) return position; + bool *is_space) { + if (position <= 0) + return position; auto c = Utf16PreviousCodePoint(str, position, nullptr); - if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). - if (is_space) *is_space = true; + if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). + if (is_space) + *is_space = true; return Utf16BackwardUntil(str, position, [](CodePoint c) { return !IsSpace(c); }); } else { - if (is_space) *is_space = false; + if (is_space) + *is_space = false; return Utf16BackwardUntil(str, position, IsSpace); } } gsl::index Utf16NextWord(std::u16string_view str, gsl::index position, - bool* is_space) { - if (position >= static_cast(str.size())) return position; + bool *is_space) { + if (position >= static_cast(str.size())) + return position; auto c = Utf16NextCodePoint(str, position, nullptr); - if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). - if (is_space) *is_space = true; + if (IsSpace(c)) { // TODO: Currently only test against 0x20(space). + if (is_space) + *is_space = true; return Utf16ForwardUntil(str, position, [](CodePoint c) { return !IsSpace(c); }); } else { - if (is_space) *is_space = false; + if (is_space) + *is_space = false; return Utf16ForwardUntil(str, position, IsSpace); } } @@ -313,13 +341,15 @@ char16_t ToUpper(char16_t c) { std::u16string ToLower(std::u16string_view s) { std::u16string result; - for (auto c : s) result.push_back(ToLower(c)); + for (auto c : s) + result.push_back(ToLower(c)); return result; } std::u16string ToUpper(std::u16string_view s) { std::u16string result; - for (auto c : s) result.push_back(ToUpper(c)); + for (auto c : s) + result.push_back(ToUpper(c)); return result; } -} // namespace cru +} // namespace cru diff --git a/works/life/computer-network-experiment/StringUtil.hpp b/works/life/computer-network-experiment/StringUtil.hpp index 1a9634a..b0ca675 100644 --- a/works/life/computer-network-experiment/StringUtil.hpp +++ b/works/life/computer-network-experiment/StringUtil.hpp @@ -130,6 +130,7 @@ std::string ToUtf8(std::u16string_view s); std::u16string ToUtf16(std::string_view s); #ifdef WIN32 +std::string ToUtf8(std::wstring_view s); std::wstring ToUtf16WString(std::string_view s); #endif diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index 489948f..c25a26b 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -45,7 +45,7 @@ int Main() { } name.push_back(CRUT('\n')); - String name_data = ConvertCharString(name); + auto name_data = ConvertCharStringBack(name); SafeSend(client_socket, name_data); CloseSocket(client_socket); -- cgit v1.2.3 From 9c42586bc406015be0145576fd6cb3586686b4ca Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 7 Jun 2021 23:24:43 +0800 Subject: import(life): ... --- .../computer-network-experiment/CMakeLists.txt | 2 +- works/life/computer-network-experiment/Common.cpp | 8 +-- works/life/computer-network-experiment/Common.h | 5 +- works/life/computer-network-experiment/IO.cpp | 80 ++++++++++++++++++++++ works/life/computer-network-experiment/IO.h | 66 ++++++++++++++++++ works/life/computer-network-experiment/Output.cpp | 76 -------------------- works/life/computer-network-experiment/Output.h | 67 ------------------ works/life/computer-network-experiment/client.cpp | 2 +- works/life/computer-network-experiment/server.cpp | 24 +++++-- 9 files changed, 172 insertions(+), 158 deletions(-) create mode 100644 works/life/computer-network-experiment/IO.cpp create mode 100644 works/life/computer-network-experiment/IO.h delete mode 100644 works/life/computer-network-experiment/Output.cpp delete mode 100644 works/life/computer-network-experiment/Output.h (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/CMakeLists.txt b/works/life/computer-network-experiment/CMakeLists.txt index 4d4277c..09c1ea4 100644 --- a/works/life/computer-network-experiment/CMakeLists.txt +++ b/works/life/computer-network-experiment/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_CXX_STANDARD 17) find_package(fmt CONFIG REQUIRED) find_package(Microsoft.GSL CONFIG REQUIRED) -add_library(base STATIC Common.cpp StringUtil.cpp Output.cpp) +add_library(base STATIC Common.cpp StringUtil.cpp IO.cpp) target_link_libraries(base PUBLIC Microsoft.GSL::GSL fmt::fmt Folly::folly) if(WIN32) target_link_libraries(base PUBLIC Ws2_32) diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp index e4615fc..ec6fd1a 100644 --- a/works/life/computer-network-experiment/Common.cpp +++ b/works/life/computer-network-experiment/Common.cpp @@ -1,6 +1,6 @@ #include "Common.h" -#include "Output.h" +#include "IO.h" #ifdef WIN32 #include @@ -70,12 +70,6 @@ void BeforeExit() { SignalAndWaitForOutputThreadStop(); } -String ReadInputLine() { - String line; - std::getline(input_stream, line); - return line; -} - void SafeSend(int socket, std::string_view buffer) { const int total_byte_count = buffer.size(); int byte_count_sent = 0; diff --git a/works/life/computer-network-experiment/Common.h b/works/life/computer-network-experiment/Common.h index 6886e38..d2f2e52 100644 --- a/works/life/computer-network-experiment/Common.h +++ b/works/life/computer-network-experiment/Common.h @@ -2,6 +2,7 @@ #include "StringUtil.hpp" #include +#include #include #include @@ -9,6 +10,7 @@ using Char = wchar_t; using String = std::wstring; using StringView = std::wstring_view; +using StringStream = std::wstringstream; inline auto &input_stream = std::wcin; inline auto &output_stream = std::wcout; inline auto &error_stream = std::wcerr; @@ -25,6 +27,7 @@ inline std::string ConvertCharStringBack(StringView s) { using Char = char; using String = std::string; using StringView = std::string_view; +using StringStream = std::stringstream; inline auto &input_stream = std::cin; inline auto &output_stream = std::cout; inline auto &error_stream = std::cerr; @@ -43,7 +46,5 @@ int CloseSocket(int socket); void BeforeExit(); -String ReadInputLine(); - void SafeSend(int socket, std::string_view buffer); std::string SafeReadUntil(int socket, char c, std::string &rest); diff --git a/works/life/computer-network-experiment/IO.cpp b/works/life/computer-network-experiment/IO.cpp new file mode 100644 index 0000000..0c20537 --- /dev/null +++ b/works/life/computer-network-experiment/IO.cpp @@ -0,0 +1,80 @@ +#include "IO.h" + +#include + +#include +#include +#include +#include + +folly::MPMCQueue output_queue(100); + +folly::CancellationSource cancellation_source; + +std::thread io_thread; + +void PrintOutput(const Output &output) { + std::basic_ostream *stream; + + switch (output.type) { + case OutputType::Error: + stream = &error_stream; + break; + default: + stream = &output_stream; + break; + } + + switch (output.color) { + case OutputColor::Normal: + (*stream) << output.message; + break; + case OutputColor::Green: + (*stream) << CRUT("\x1b[32m") << output.message << CRUT("\x1b[39m") + << std::flush; + break; + case OutputColor::Red: + (*stream) << CRUT("\x1b[31m") << output.message << CRUT("\x1b[39m") + << std::flush; + break; + case OutputColor::Yellow: + (*stream) << CRUT("\x1b[33m") << output.message << CRUT("\x1b[39m") + << std::flush; + break; + } +} + +String ReadInputLine() { + String line; + std::getline(input_stream, line); + return line; +} + +void IOThread() { + while (true) { + if (cancellation_source.isCancellationRequested()) { + while (true) { + Output output; + if (output_queue.readIfNotEmpty(output)) { + PrintOutput(output); + } else { + return; + } + } + } + + Output output; + while (output_queue.readIfNotEmpty(output)) + PrintOutput(output); + + PrintOutput({CRUT("> ")}); + OnInputLine(ReadInputLine()); + } +} + +void SignalAndWaitForOutputThreadStop() { + cancellation_source.requestCancellation(); + io_thread.join(); +} + +void StartIOThread() { io_thread = std::thread(IOThread); } diff --git a/works/life/computer-network-experiment/IO.h b/works/life/computer-network-experiment/IO.h new file mode 100644 index 0000000..b0cf489 --- /dev/null +++ b/works/life/computer-network-experiment/IO.h @@ -0,0 +1,66 @@ +#pragma once +#include "Common.h" +#include "StringUtil.hpp" + +#include +#include +#include +#include + +#include +#include + +enum class OutputType { Normal, Error }; +enum class OutputColor { Normal, Green, Red, Yellow }; + +struct Output { + Output() = default; + Output(String message, OutputType type = OutputType::Normal) + : message(std::move(message)), type(type), + color(type == OutputType::Error ? OutputColor::Red + : OutputColor::Normal) {} + + Output(String message, OutputColor color) + : message(std::move(message)), type(OutputType::Normal), color(color) {} + + Output(String message, OutputType type, OutputColor color) + : message(std::move(message)), type(type), color(color) {} + + CRU_DEFAULT_COPY(Output) + CRU_DEFAULT_MOVE(Output) + ~Output() = default; + + String message; + OutputType type; + OutputColor color; +}; + +extern folly::MPMCQueue output_queue; + +inline void SendOutput(Output output) { + output_queue.blockingWrite(std::move(output)); +} + +inline void SendOutput(String output) { SendOutput(Output{std::move(output)}); } + +template void SendOutput(StringView format, Args &&...args) { + output_queue.blockingWrite(fmt::format(format, std::forward(args)...)); +} + +template +void SendOutput(OutputType type, StringView format, Args &&...args) { + output_queue.blockingWrite( + Output{fmt::format(format, std::forward(args)...), type}); +} + +template +void SendOutput(OutputColor color, StringView format, Args &&...args) { + output_queue.blockingWrite( + Output{fmt::format(format, std::forward(args)...), color}); +} + +void SignalAndWaitForOutputThreadStop(); + +void OnInputLine(StringView line); + +void StartIOThread(); diff --git a/works/life/computer-network-experiment/Output.cpp b/works/life/computer-network-experiment/Output.cpp deleted file mode 100644 index fbbd6ba..0000000 --- a/works/life/computer-network-experiment/Output.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "Output.h" - -#include - -#include -#include -#include - -std::mutex m; - -folly::MPMCQueue output_queue(100); - -folly::CancellationSource cancellation_source; - -std::thread output_thread(OutputThread); - -void PrintOutput(const Output &output) { - std::basic_ostream *stream; - - switch (output.type) { - case OutputType::Error: - stream = &error_stream; - break; - default: - stream = &output_stream; - break; - } - - switch (output.color) { - case OutputColor::Normal: - (*stream) << output.message; - break; - case OutputColor::Green: - (*stream) << CRUT("\x1b[32m") << output.message << CRUT("\x1b[39m") - << std::flush; - break; - case OutputColor::Red: - (*stream) << CRUT("\x1b[31m") << output.message << CRUT("\x1b[39m") - << std::flush; - break; - case OutputColor::Yellow: - (*stream) << CRUT("\x1b[33m") << output.message << CRUT("\x1b[39m") - << std::flush; - break; - } -} - -void OutputThread() { - while (true) { - std::lock_guard guard(m); - - if (cancellation_source.getToken().isCancellationRequested()) { - while (true) { - Output output; - if (output_queue.readIfNotEmpty(output)) { - PrintOutput(output); - } else { - return; - } - } - } - - Output output; - if (output_queue.readIfNotEmpty(output)) - PrintOutput(output); - } -} - -void SignalAndWaitForOutputThreadStop() { - cancellation_source.requestCancellation(); - output_thread.join(); -} - -std::lock_guard BlockOutputThread() { - return std::lock_guard(m); -} diff --git a/works/life/computer-network-experiment/Output.h b/works/life/computer-network-experiment/Output.h deleted file mode 100644 index 689c3d3..0000000 --- a/works/life/computer-network-experiment/Output.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once -#include "Common.h" -#include "StringUtil.hpp" - -#include -#include -#include -#include - -#include -#include -#include - -enum class OutputType { Normal, Error }; -enum class OutputColor { Normal, Green, Red, Yellow }; - -struct Output { - Output() = default; - Output(String message, OutputType type = OutputType::Normal) - : message(std::move(message)), type(type), - color(type == OutputType::Error ? OutputColor::Red - : OutputColor::Normal) {} - - Output(String message, OutputColor color) - : message(std::move(message)), type(OutputType::Normal), color(color) {} - - Output(String message, OutputType type, OutputColor color) - : message(std::move(message)), type(type), color(color) {} - - CRU_DEFAULT_COPY(Output) - CRU_DEFAULT_MOVE(Output) - ~Output() = default; - - String message; - OutputType type; - OutputColor color; -}; - -extern folly::MPMCQueue output_queue; - -inline void SendOutput(Output output) { - output_queue.blockingWrite(std::move(output)); -} - -inline void SendOutput(String output) { SendOutput(Output{std::move(output)}); } - -template void SendOutput(StringView format, Args &&...args) { - output_queue.blockingWrite(fmt::format(format, std::forward(args)...)); -} - -template -void SendOutput(OutputType type, StringView format, Args &&...args) { - output_queue.blockingWrite( - Output{fmt::format(format, std::forward(args)...), type}); -} - -template -void SendOutput(OutputColor color, StringView format, Args &&...args) { - output_queue.blockingWrite( - Output{fmt::format(format, std::forward(args)...), color}); -} - -void OutputThread(); - -void SignalAndWaitForOutputThreadStop(); - -std::lock_guard BlockOutputThread(); diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index c25a26b..a8ce8cf 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -3,7 +3,7 @@ */ #include "Common.h" -#include "Output.h" +#include "IO.h" #ifdef WIN32 #include diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index 3c87ea0..7008c7b 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -3,8 +3,7 @@ */ #include "Common.h" -#include "Output.h" -#include "fmt/core.h" +#include "IO.h" #include #include @@ -25,7 +24,15 @@ const auto bind_address = "127.0.0.1"; // control bind address const u_short port = 1234; // control bind port +void PrintHelp() { + SendOutput(CRUT( + "Input and run one of following command:\n\t> NOTHING -> Continue and " + "print new messages.\n\t> list -> List all connected client.\n\t> send " + "[i] [message] -> Send messages to client with number i.\n")); +} + struct Connection { + int id; std::thread thread; int socket; sockaddr_in address; @@ -35,6 +42,8 @@ struct Connection { folly::CancellationSource cancellation_source; }; +std::vector connections; + void ResponseThreadProc(Connection *connection) { auto host = ConvertCharString(inet_ntoa(connection->address.sin_addr)); auto port = htons(connection->address.sin_port); @@ -77,9 +86,11 @@ void ResponseThreadProc(Connection *connection) { CloseSocket(connection->socket); } -int Main() { - std::vector connections; +void OnInputLine(StringView line) { StringStream ss{String(line)}; + ss. + } +int Main() { int server_socket; if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { @@ -105,6 +116,10 @@ int Main() { SendOutput(OutputColor::Green, CRUT("Now start to accept incoming connection.\n")); + StartIOThread(); + + int current_id = 1; + while (true) { sockaddr_in client_address; int client_socket; @@ -121,6 +136,7 @@ int Main() { } Connection connection; + connection.id = current_id++; connection.socket = client_socket; connection.address = client_address; connections.push_back(std::move(connection)); -- cgit v1.2.3 From 68cac85ea58c69301645167f92d94bdb6e360753 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 8 Jun 2021 10:16:22 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/IO.cpp | 3 +- works/life/computer-network-experiment/IO.h | 2 + works/life/computer-network-experiment/client.cpp | 59 ++++++++++++-- works/life/computer-network-experiment/server.cpp | 94 ++++++++++++++++++++--- 4 files changed, 138 insertions(+), 20 deletions(-) (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/IO.cpp b/works/life/computer-network-experiment/IO.cpp index 0c20537..5d3fe12 100644 --- a/works/life/computer-network-experiment/IO.cpp +++ b/works/life/computer-network-experiment/IO.cpp @@ -9,9 +9,10 @@ folly::MPMCQueue output_queue(100); +namespace { folly::CancellationSource cancellation_source; - std::thread io_thread; +} void PrintOutput(const Output &output) { std::basic_ostream *stream; diff --git a/works/life/computer-network-experiment/IO.h b/works/life/computer-network-experiment/IO.h index b0cf489..1658b78 100644 --- a/works/life/computer-network-experiment/IO.h +++ b/works/life/computer-network-experiment/IO.h @@ -64,3 +64,5 @@ void SignalAndWaitForOutputThreadStop(); void OnInputLine(StringView line); void StartIOThread(); + +String ReadInputLine(); \ No newline at end of file diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index a8ce8cf..c206856 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -5,6 +5,9 @@ #include "Common.h" #include "IO.h" +#include +#include + #ifdef WIN32 #include #include @@ -12,12 +15,29 @@ #include #include #include - #endif const auto connect_address = "127.0.0.1"; // control connect address const u_short port = 1234; // control connect port +namespace { +folly::ProducerConsumerQueue send_queue(100); +folly::CancellationSource cancellation_source; +} // namespace + +void PrintHelp() { + SendOutput(CRUT("Input anything to send to server. Or just enter to receive " + "lastest messages from server.\n")); +} + +void OnInputLine(StringView line) { + if (line.empty()) { + return; + } else { + send_queue.write(ConvertCharStringBack(line) + '\n'); + } +} + int Main() { int client_socket; @@ -37,17 +57,42 @@ int Main() { PrintErrorMessageAndExit(CRUT("Failed to connect!")); } - String name; - { - auto guard = BlockOutputThread(); - output_stream << CRUT("Please input your name:"); - name = ReadInputLine(); - } + output_stream << CRUT("Please input your name:\n> "); + String name = ReadInputLine(); + + PrintHelp(); + + StartIOThread(); name.push_back(CRUT('\n')); auto name_data = ConvertCharStringBack(name); SafeSend(client_socket, name_data); + std::thread receive_thread([client_socket] { + std::string rest; + while (true) { + if (cancellation_source.isCancellationRequested()) { + break; + } + + std::string s = SafeReadUntil(client_socket, '\n', rest); + + SendOutput(CRUT("Recived a message:\n{}\n"), ConvertCharString(s)); + } + }); + receive_thread.detach(); + + while (true) { + if (cancellation_source.isCancellationRequested()) { + break; + } + + std::string s; + if (send_queue.read(s)) { + SafeSend(client_socket, s); + } + } + CloseSocket(client_socket); return 0; } diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index 7008c7b..9654687 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -42,7 +44,20 @@ struct Connection { folly::CancellationSource cancellation_source; }; -std::vector connections; +std::vector> connections; + +void PrintConnections() { + if (connections.empty()) { + SendOutput(CRUT("Currently there is no connection.\n")); + } + + String s; + for (const auto &connection : connections) { + s += fmt::format(CRUT("{}: {}({})\n"), connection->id, connection->name, + connection->address_string); + } + SendOutput(s); +} void ResponseThreadProc(Connection *connection) { auto host = ConvertCharString(inet_ntoa(connection->address.sin_addr)); @@ -53,7 +68,7 @@ void ResponseThreadProc(Connection *connection) { std::string n = SafeReadUntil(connection->socket, '\n', rest); connection->name = ConvertCharString(n); - SendOutput(CRUT("Connected to {}, whose name is {}."), + SendOutput(OutputColor::Green, CRUT("Connected to {}, whose name is {}.\n"), connection->address_string, connection->name); std::thread revieve_thread( @@ -71,6 +86,7 @@ void ResponseThreadProc(Connection *connection) { } }, connection); + revieve_thread.detach(); while (true) { if (connection->cancellation_source.isCancellationRequested()) { @@ -86,9 +102,60 @@ void ResponseThreadProc(Connection *connection) { CloseSocket(connection->socket); } -void OnInputLine(StringView line) { StringStream ss{String(line)}; - ss. - } +void OnInputLine(StringView line) { + StringStream ss{String(line)}; + + ss >> std::ws; + if (ss.eof()) + return; + + String command; + ss >> command; + + if (command == CRUT("list")) { + if (!ss.eof()) { + SendOutput(OutputType::Error, + CRUT("List command can't have arguments!\n")); + PrintHelp(); + } else { + PrintConnections(); + } + return; + } else if (command == CRUT("send")) { + int id; + ss >> id; + if (!ss) { + SendOutput(OutputType::Error, CRUT("Send format error!\n")); + PrintHelp(); + return; + } + + String message; + getline(ss, message); + + if (message.empty()) { + SendOutput(OutputType::Error, CRUT("Send message can't be empty.!\n")); + PrintHelp(); + return; + } + + auto i = std::find_if( + connections.begin(), connections.end(), + [id](const std::unique_ptr &c) { return c->id == id; }); + + if (i == connections.end()) { + SendOutput(OutputType::Error, CRUT("No connection with such id.!\n")); + return; + } + + (*i)->send_queue.write(ConvertCharStringBack(message) + "\n"); + return; + } else { + SendOutput(OutputType::Error, CRUT("Unkown command!\n")); + PrintHelp(); + return; + } +} int Main() { int server_socket; @@ -116,6 +183,8 @@ int Main() { SendOutput(OutputColor::Green, CRUT("Now start to accept incoming connection.\n")); + PrintHelp(); + StartIOThread(); int current_id = 1; @@ -135,13 +204,14 @@ int Main() { PrintErrorMessageAndExit(CRUT("Failed to accecpt.")); } - Connection connection; - connection.id = current_id++; - connection.socket = client_socket; - connection.address = client_address; - connections.push_back(std::move(connection)); + connections.push_back(std::make_unique()); + const std::unique_ptr &connection = connections.back(); - connection.thread = std::thread(ResponseThreadProc, &connections.back()); - connection.thread.detach(); + connection->id = current_id++; + connection->socket = client_socket; + connection->address = client_address; + connection->thread = + std::thread(ResponseThreadProc, connections.back().get()); + connection->thread.detach(); } } -- cgit v1.2.3 From f7d73f1bf08aaca98e789a6d6c56d672cc0c4c9f Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 8 Jun 2021 18:25:36 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/Common.cpp | 33 ++++++++++------------ works/life/computer-network-experiment/Common.h | 6 ++-- works/life/computer-network-experiment/client.cpp | 11 ++++++-- works/life/computer-network-experiment/server.cpp | 34 ++++++++++++++++++----- 4 files changed, 53 insertions(+), 31 deletions(-) (limited to 'works/life/computer-network-experiment/client.cpp') diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp index ec6fd1a..1df4d56 100644 --- a/works/life/computer-network-experiment/Common.cpp +++ b/works/life/computer-network-experiment/Common.cpp @@ -1,6 +1,7 @@ #include "Common.h" #include "IO.h" +#include #ifdef WIN32 #include @@ -70,7 +71,7 @@ void BeforeExit() { SignalAndWaitForOutputThreadStop(); } -void SafeSend(int socket, std::string_view buffer) { +bool SafeSend(int socket, std::string_view buffer) { const int total_byte_count = buffer.size(); int byte_count_sent = 0; int retry_count = 0; @@ -78,55 +79,49 @@ void SafeSend(int socket, std::string_view buffer) { while (true) { // Now we have sent all data. if (byte_count_sent == total_byte_count) - break; + return true; auto byte_actually_sent = send(socket, buffer.data() + byte_count_sent, buffer.size() - byte_count_sent, 0); // send failed if (byte_actually_sent == -1) { - SendOutput(OutputType::Error, CRUT("Failed to send!\n")); - CloseSocket(socket); - break; + return false; } byte_count_sent += byte_actually_sent; } } -std::string SafeReadUntil(int socket, char c, std::string &rest) { - std::string result = rest; +bool SafeReadUntil(int socket, char c, std::string &data, std::string &rest) { + data = rest; const int buffer_size = 100; - char *buffer = new char[buffer_size]; + char buffer[buffer_size]; while (true) { int received_number = recv(socket, buffer, buffer_size, 0); if (received_number == -1) { - PrintErrorMessageAndExit(CRUT("Failed to recv.")); + return false; } - bool b = false; + bool end = false; for (int i = 0; i < received_number; i++) { if (buffer[i] == c) { - result.append(buffer, i); + data.append(buffer, i); rest = std::string(buffer + i + 1, received_number - i - 1); - b = true; + end = true; break; } } - if (b) - break; + if (end) + return true; - result.append(buffer, received_number); + data.append(buffer, received_number); } - - delete[] buffer; - - return result; } int main() { diff --git a/works/life/computer-network-experiment/Common.h b/works/life/computer-network-experiment/Common.h index a4472c7..1e6c277 100644 --- a/works/life/computer-network-experiment/Common.h +++ b/works/life/computer-network-experiment/Common.h @@ -48,5 +48,7 @@ int CloseSocket(int socket); void BeforeExit(); -void SafeSend(int socket, std::string_view buffer); -std::string SafeReadUntil(int socket, char c, std::string &rest); +// Return false for error. +bool SafeSend(int socket, std::string_view buffer); +// Return false for error. +bool SafeReadUntil(int socket, char c, std::string &data, std::string &rest); diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp index c206856..73ae52f 100644 --- a/works/life/computer-network-experiment/client.cpp +++ b/works/life/computer-network-experiment/client.cpp @@ -75,9 +75,12 @@ int Main() { break; } - std::string s = SafeReadUntil(client_socket, '\n', rest); + std::string data; + if (!SafeReadUntil(client_socket, '\n', data, rest)) { + PrintErrorMessageAndExit(CRUT("Failed to receive message.\n")); + } - SendOutput(CRUT("Recived a message:\n{}\n"), ConvertCharString(s)); + SendOutput(CRUT("Recived a message:\n{}\n"), ConvertCharString(data)); } }); receive_thread.detach(); @@ -89,7 +92,9 @@ int Main() { std::string s; if (send_queue.read(s)) { - SafeSend(client_socket, s); + if (!SafeSend(client_socket, s)) { + PrintErrorMessageAndExit(CRUT("Failed to send message to server.")); + } } } diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index 9654687..03d27ad 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -36,6 +36,7 @@ void PrintHelp() { struct Connection { int id; std::thread thread; + std::thread receive_thread; int socket; sockaddr_in address; String address_string; @@ -65,13 +66,19 @@ void ResponseThreadProc(Connection *connection) { connection->address_string = fmt::format(CRUT("{}:{}"), host, port); std::string rest; + std::string name_data; + if (!SafeReadUntil(connection->socket, '\n', name_data, rest)) { + SendOutput(OutputType::Error, CRUT("Failed to read name of {}.\n"), + connection->address_string); + CloseSocket(connection->socket); + return; + } - std::string n = SafeReadUntil(connection->socket, '\n', rest); - connection->name = ConvertCharString(n); + connection->name = ConvertCharString(name_data); SendOutput(OutputColor::Green, CRUT("Connected to {}, whose name is {}.\n"), connection->address_string, connection->name); - std::thread revieve_thread( + connection->receive_thread = std::thread( [](Connection *connection) { std::string rest; while (true) { @@ -79,14 +86,22 @@ void ResponseThreadProc(Connection *connection) { break; } - std::string s = SafeReadUntil(connection->socket, '\n', rest); + std::string data; + + if (!SafeReadUntil(connection->socket, '\n', data, rest)) { + SendOutput(OutputType::Error, + CRUT("Failed read data from socket of {}({}).\n"), + connection->name, connection->address_string); + connection->cancellation_source.requestCancellation(); + return; + } SendOutput(CRUT("{}({}) send a message:\n{}\n"), connection->name, - connection->address_string, ConvertCharString(s)); + connection->address_string, ConvertCharString(data)); } }, connection); - revieve_thread.detach(); + connection->receive_thread.detach(); while (true) { if (connection->cancellation_source.isCancellationRequested()) { @@ -95,7 +110,12 @@ void ResponseThreadProc(Connection *connection) { std::string s; if (connection->send_queue.read(s)) { - SafeSend(connection->socket, s); + if (!SafeSend(connection->socket, s)) { + SendOutput(OutputType::Error, CRUT("Failed send data to {}({}).\n"), + connection->name, connection->address_string); + connection->cancellation_source.requestCancellation(); + break; + } } } -- cgit v1.2.3