From 05c9569586b18b0a276fceb65f0464c0c524b05c Mon Sep 17 00:00:00 2001 From: mezzode Date: Sun, 10 Nov 2019 16:59:32 -0800 Subject: [PATCH] Implement multithreading on server --- .gitignore | 1 + client.cpp | 12 ++++++++++ client.h | 4 +++- common.h | 2 ++ server.cpp | 68 +++++++++++++++++++++++++++++++++++------------------- server.h | 1 + 6 files changed, 63 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 2b4392f..13c64ae 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ CTestTestfile.cmake _deps .vs out +CMakeSettings.json diff --git a/client.cpp b/client.cpp index bf92ee2..0e33ca3 100644 --- a/client.cpp +++ b/client.cpp @@ -29,3 +29,15 @@ void sendHeader(HANDLE h, string key) { } cout << "Sent header." << endl; } + +bool awaitSendSuccess(HANDLE h) { + std::vector buf(bufSize); + + DWORD bytesRead; + const BOOL readSuccess = ReadFile(h, buf.data(), buf.size(), &bytesRead, nullptr); // Use ReadFileEx for async + if (!readSuccess) { + throw GetLastError(); + } + + return string{ buf.data(), bytesRead } == saveSuccessStatus; +} diff --git a/client.h b/client.h index 3471445..38287a9 100644 --- a/client.h +++ b/client.h @@ -13,6 +13,7 @@ using std::string; void sendHeader(HANDLE h, string key); +bool awaitSendSuccess(HANDLE h); template void send(string key, T data) { @@ -41,9 +42,10 @@ void send(string key, T data) { sendHeader(h, key); sendData(h, data); + const bool success = awaitSendSuccess(h); CloseHandle(h); - cout << "Send success." << endl; + cout << "Send " << (success ? "success" : "fail") << endl; } template diff --git a/common.h b/common.h index 608b7ef..87f3ff3 100644 --- a/common.h +++ b/common.h @@ -19,3 +19,5 @@ struct Action { archive(type, key); } }; + +const std::string saveSuccessStatus{ "saveSuccess" }; diff --git a/server.cpp b/server.cpp index 4de690f..2e107a7 100644 --- a/server.cpp +++ b/server.cpp @@ -2,6 +2,7 @@ // #include +#include #include #include #include @@ -15,26 +16,25 @@ int main() { cout << "I am the server." << endl; + // TODO: add mutex. stl allows multiple threads reading and one writing auto store = unordered_map{}; - const DWORD pipeMode{ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT }; - // don't use PIPE_NOWAIT for async, see https://docs.microsoft.com/en-us/windows/win32/ipc/synchronous-and-overlapped-input-and-output - - const HANDLE h{ CreateNamedPipe( - pipeName, - PIPE_ACCESS_DUPLEX, - pipeMode, - PIPE_UNLIMITED_INSTANCES, - bufSize, - bufSize, - 0, - nullptr - ) }; - if (h == INVALID_HANDLE_VALUE) { - throw GetLastError(); - } - while (TRUE) { + const DWORD pipeMode{ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT }; + const HANDLE h{ CreateNamedPipe( + pipeName, + PIPE_ACCESS_DUPLEX, + pipeMode, + PIPE_UNLIMITED_INSTANCES, + bufSize, + bufSize, + 0, + nullptr + ) }; + if (h == INVALID_HANDLE_VALUE) { + throw GetLastError(); + } + const BOOL success = ConnectNamedPipe(h, nullptr); if (!success) { cout << "0x" << hex << GetLastError() << endl; @@ -42,13 +42,16 @@ int main() } cout << "Connected." << endl; - read(h, store); - - const BOOL dSuccess = DisconnectNamedPipe(h); - if (!dSuccess) { - cout << "0x" << hex << GetLastError() << endl; - throw GetLastError(); - } + // create a separate thread so can handle clients asynchronously + thread{[h, &store]() { + read(h, store); + const BOOL dSuccess = DisconnectNamedPipe(h); + if (!dSuccess) { + cout << "0x" << hex << GetLastError() << endl; + throw GetLastError(); + } + CloseHandle(h); + }}.detach(); } } @@ -59,6 +62,7 @@ void read(HANDLE h, Store &store) { cout << "Saving data for key " << action.key << endl; store[action.key] = readData(h); cout << "Saved data for key " << action.key << endl; + saveSuccess(h); break; } case Type::Get: { @@ -70,6 +74,22 @@ void read(HANDLE h, Store &store) { } } +void saveSuccess(HANDLE h) { + DWORD bytesWritten{ 0 }; + const BOOL success = WriteFile( + h, + &saveSuccessStatus[0], + saveSuccessStatus.size(), + &bytesWritten, + nullptr + ); + FlushFileBuffers(h); + if (!success) { + cout << "0x" << hex << GetLastError() << endl; + throw GetLastError(); + } +} + void returnData(HANDLE h, string data) { DWORD bytesWritten{ 0 }; const BOOL success = WriteFile( diff --git a/server.h b/server.h index 936f1b2..546fc9a 100644 --- a/server.h +++ b/server.h @@ -16,3 +16,4 @@ void read(HANDLE h, Store &store); Action readHeader(HANDLE h); string readData(HANDLE h); void returnData(HANDLE h, string data); +void saveSuccess(HANDLE h);