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(-) 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