2014-12-07 115 views
4

我已經命名了使用boost asio編寫的管道服務器。服務器創建命名管道並調用ConnectNamedPipe,將asio重疊的ptr傳遞給它。問題是傳遞給asio的完成處理程序從不會被調用,即在客戶端調用CreateFile將不會觸發傳遞給ConnectNamedPipe的完成處理程序。我究竟做錯了什麼?ConnectNamedPipe和asio重疊ptr

這是客戶端和服務器的完整清單:

#define _WIN32_WINNT 0x0501 
#include <string> 
#include <functional> 
#include <thread> 
#include <boost/system/error_code.hpp> 
#include <boost/asio/io_service.hpp> 
#include <boost/asio/windows/overlapped_ptr.hpp> 
#include <boost/bind.hpp> 
#include <tchar.h> 

#include <Windows.h> 

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::string   PIPE_NAME = "\\\\.\\pipe\\BC33AFC8-BA51-4DCD-9507-0234785D4F55_native_server_pipe"; 


class Server 
    : public std::enable_shared_from_this<Server> 
{ 
public: 
    Server(){} 
    ~Server(){} 

    void Start() 
    { 
     mIoService = std::make_shared<boost::asio::io_service>(); 
     mWork = std::make_shared<boost::asio::io_service::work>(*mIoService); 
     mThread = std::make_shared<std::thread>(
      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<boost::asio::io_service>  mIoService; 
    std::shared_ptr<boost::asio::io_service::work> mWork; 
    std::shared_ptr<std::thread>     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<Server> s = std::make_shared<Server>(); 
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); 
} 
+0

在Server :: Start方法中的線程之前創建了io_service :: work對象 – iendgame 2014-12-08 19:07:12

回答

2

發現的問題。在服務器部分,我沒有將管道與IOCP本身關聯起來。這可以通過在調用ConnectNamedPipe之前將CreateNamedPipeA返回的管本機句柄包裝到boost::asio::windows::stream_handle中來完成。

typedef boost::asio::windows::stream_handle StreamHandler; 
std::shared_ptr<StreamHandler> streamHandler = std::make_shared<StreamHandler>(*mIoService); 
streamHandle->assign(pipe);