From f0309ee1e5cd268091f59f3aa377beca77d76c5c Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 6 Jun 2021 22:05:28 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/Common.cpp | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 works/life/computer-network-experiment/Common.cpp (limited to 'works/life/computer-network-experiment/Common.cpp') diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp new file mode 100644 index 0000000..02ac550 --- /dev/null +++ b/works/life/computer-network-experiment/Common.cpp @@ -0,0 +1,48 @@ +#include "Common.h" + +#include "Output.h" + +#ifdef WIN32 +#include +#include +#pragma comment(lib, "Ws2_32.lib") +#endif + +[[noreturn]] void PrintErrorMessageAndExit(StringView message, + bool print_last_error) { + + SendOutput(CRUT("{}\n"), message); + + if (print_last_error) { +#ifdef WIN32 + auto error_code = WSAGetLastError(); + SendOutput(OutputType::Error, CRUT("Error code is {}.\n"), error_code); + wchar_t buffer[500]; + if (!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, error_code, 0, buffer, 500, nullptr)) { + SendOutput(OutputType::Error, CRUT("Failed to format error message.\n")); + } else { + SendOutput(OutputType::Error, CRUT("{}\n"), buffer); + } +#else +#endif + } + +#ifdef WIN32 + WSACleanup(); +#endif + + std::exit(1); +} + +#ifdef WIN32 +void InitWSA() { + WSADATA wsa_data; + + if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) { // initialize wsa + PrintErrorMessageAndExit(CRUT("Failed to initialize wsa.")); + } +} +#endif -- 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/Common.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/Common.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/Common.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 0dd20e5dde39d1cc42ca5c92f56cdb087c1b8f00 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 7 Jun 2021 14:21:14 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/Common.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'works/life/computer-network-experiment/Common.cpp') diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp index fbdb2c8..5be3971 100644 --- a/works/life/computer-network-experiment/Common.cpp +++ b/works/life/computer-network-experiment/Common.cpp @@ -67,6 +67,12 @@ void BeforeExit() { int main() { #ifdef WIN32 + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD mode; + GetConsoleMode(h, &mode); + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(h, mode); + InitWSA(); #endif -- 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/Common.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/Common.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 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/Common.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 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/Common.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