J’ai nommé pipe server qui est écrit en utilisant asio de boost. Le serveur crée un canal nommé et les appels ConnectNamedPipe passant asio se superposent à lui. Le problème est que le gestionnaire d’achèvement transmis à asio overlapped n’est jamais appelé, cela appelle CreateFile côté client ne déclenchera pas le gestionnaire d’achèvement transmis à ConnectNamedPipe. Qu’est-ce que je fais mal?
Voici la liste complète des clients et des serveurs:
#define _WIN32_WINNT 0x0501 #include #include #include #include #include #include #include #include #include static const uint32_t PIPE_OUTPUT_BUFFER_RESERVED_SIZE_BYTES = 50 * 1024; static const uint32_t PIPE_INPUT_BUFFER_RESERVED_SIZE_BYTES = 50 * 1024; static const std::ssortingng PIPE_NAME = "\\\\.\\pipe\\BC33AFC8-BA51-4DCD-9507-0234785D4F55_native_server_pipe"; class Server : public std::enable_shared_from_this { public: Server(){} ~Server(){} void Start() { mIoService = std::make_shared(); mWork = std::make_shared(*mIoService); mThread = std::make_shared( boost::bind(&boost::asio::io_service::run, mIoService)); mIoService->post(boost::bind(&Server::Accept, shared_from_this())); } void Accept() { mPipe = CreateNamedPipeA( PIPE_NAME.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, PIPE_UNLIMITED_INSTANCES, PIPE_OUTPUT_BUFFER_RESERVED_SIZE_BYTES, PIPE_INPUT_BUFFER_RESERVED_SIZE_BYTES, 0, nullptr); if (mPipe == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); //LOG(Error, "Failed create pipe: " << mPipeName << ", error: " << err); return; } //LOG(Trace, "Pipe: " << mPipeName << " created successfully"); boost::asio::windows::overlapped_ptr overlappedPtr(*mIoService, std::bind(&Server::OnClientConnected, this, std::placeholders::_1, std::placeholders::_2)); OVERLAPPED* overlapped = overlappedPtr.get(); BOOL ok = ConnectNamedPipe(mPipe, overlapped); DWORD lastError = GetLastError(); if (!ok && lastError != ERROR_IO_PENDING) { // The operation completed immediately, so a completion notification needs // to be posted. When complete() is called, ownership of the OVERLAPPED- // derived object passes to the io_service. boost::system::error_code ec(lastError, boost::asio::error::get_system_category()); overlappedPtr.complete(ec, 0); } else { // The operation was successfully initiated, so ownership of the // OVERLAPPED-derived object has passed to the io_service. overlappedPtr.release(); } } void OnClientConnected( const boost::system::error_code& ec, size_t bytesTransferred) { int a = 0; a++; } private: HANDLE mPipe; std::shared_ptr mIoService; std::shared_ptr mWork; std::shared_ptr mThread; }; class Client { public: void Connect() { HANDLE hPipe = CreateFileA( PIPE_NAME.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr ); if (hPipe == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); if (err != ERROR_PIPE_BUSY) { /*LOG(Error, "Failed create pipe: " << mPipeName << ", error: " << err); mOnConnected(nullptr);*/ return; } return; } } }; std::shared_ptr s = std::make_shared(); Client c; int CALLBACK WinMain( _In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow ) { s->Start(); Sleep(10000); c.Connect(); Sleep(10000); }
J’ai trouvé le problème. Je n’ai pas associé de tuyau avec IOCP
lui-même dans la partie serveur. Cela peut être fait en CreateNamedPipeA
handle natif renvoyé par CreateNamedPipeA
dans boost::asio::windows::stream_handle
juste avant d’appeler ConnectNamedPipe
.
typedef boost::asio::windows::stream_handle StreamHandler; std::shared_ptr streamHandler = std::make_shared (*mIoService); streamHandle->assign(pipe);