From 6d8fecb163a9c813a1b533970997353d33b6bf5e Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 6 Jun 2021 18:37:08 +0800 Subject: import(life): ... --- works/life/computer-network-experiment/server.cpp | 77 ++++++++++++++++++----- 1 file changed, 62 insertions(+), 15 deletions(-) (limited to 'works/life/computer-network-experiment/server.cpp') diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index 15470f4..de5bcd3 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -3,30 +3,83 @@ */ #include -#include #include -#include #include #include #include #include +#include +#include +#include + #include #include +#include "StringUtil.hpp" +#include "fmt/core.h" + #pragma comment(lib, "Ws2_32.lib") const auto bind_address = "127.0.0.1"; // control bind address const u_short port = 1234; // control bind port -// As far as I know, cout is not thread safe. So we need a lock. But this might -// not be the best solution. We can use a queue instead to avoid block. -std::mutex cout_mutex; +enum class OutputType { Normal, Error }; + +struct Output { + Output() = default; + Output(std::wstring message, OutputType type = OutputType::Normal) + : message(std::move(message)), type(type) {} + + CRU_DEFAULT_COPY(Output) + CRU_DEFAULT_MOVE(Output) + ~Output() = default; + + std::wstring message; + OutputType type; +}; + +folly::MPMCQueue output_queue; + +void SendOutput(std::wstring output) { + output_queue.blockingWrite(std::move(output)); +} + +void SendOutput(Output output) { + output_queue.blockingWrite(std::move(output)); +} + +template +void SendOutput(std::wstring_view format, Args &&...args) { + output_queue.blockingWrite(fmt::format(format, std::forward(args)...)); +} + +template +void SendOutput(OutputType type, std::wstring_view format, Args &&...args) { + output_queue.blockingWrite( + {fmt::format(format, std::forward(args)...), type}); +} + +void OutputThread() { + while (true) { + Output output; + output_queue.blockingRead(output); + switch (output.type) { + case OutputType::Error: + std::wcerr << output.message; + break; + default: + std::wcout << output.message; + break; + } + } +} [[noreturn]] void PrintErrorMessageAndExit(std::wstring_view message, std::optional error_code = std::nullopt) { - std::wcerr << message << L'\n'; + + SendOutput(L"{}\n", message); if (error_code) { std::cerr << L"Error code is " << std::hex << *error_code << L'\n'; @@ -48,10 +101,7 @@ PrintErrorMessageAndExit(std::wstring_view message, void ResponseThreadProc(int socket, sockaddr_in address) { auto address_string = inet_ntoa(address.sin_addr); - { - std::lock_guard guard(cout_mutex); - std::cout << "Connected to " << address_string << "!\n"; - } + SendOutput(L"Connected to {}!\n", cru::ToUtf16WString(address_string)); const std::string_view buffer = "Love you!!! By crupest!"; @@ -69,7 +119,6 @@ void ResponseThreadProc(int socket, sockaddr_in address) { // send failed if (byte_actually_sent == SOCKET_ERROR) { - std::lock_guard guard(cout_mutex); std::cerr << "Failed to send!\n"; closesocket(socket); break; @@ -78,10 +127,8 @@ void ResponseThreadProc(int socket, sockaddr_in address) { byte_count_sent += byte_actually_sent; } - { - std::lock_guard guard(cout_mutex); - std::cout << "Succeeded to send message to " << address_string << "!\n"; - } + SendOutput(L"Succeeded to send message to {} !\n", + cru::ToUtf16WString(address_string)); closesocket(socket); } -- cgit v1.2.3