ConnectNamedPipe 和 asio 重叠 ptr

Posted

技术标签:

【中文标题】ConnectNamedPipe 和 asio 重叠 ptr【英文标题】:ConnectNamedPipe and asio overlappped ptr 【发布时间】:2014-12-07 21:03:43 【问题描述】:

我已经命名了使用 boost asio 编写的管道服务器。服务器创建命名管道并调用 ConnectNamedPipe,将 asio 重叠 ptr 传递给它。问题是传递给 asio 重叠的完成处理程序永远不会被调用,即在客户端调用 CreateFile 不会触发传递给 ConnectNamedPipe 的完成处理程序。我做错了什么?

这是客户端和服务器的完整列表:

#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);

【问题讨论】:

在Server::Start方法的线程之前创建了io_service::work对象 【参考方案1】:

发现问题。我没有在服务器部分将管道与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);

【讨论】:

以上是关于ConnectNamedPipe 和 asio 重叠 ptr的主要内容,如果未能解决你的问题,请参考以下文章

未发出信号的非阻塞 ConnectNamedPipe 事件

BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT 宏重定义

命名管道:ConnectNamedPipe 后的 ReadFile 返回 ERROR_BROKEN_PIPE

MonsterAudio怎么调低音

什么是asio?

使用 boost::asio::async_wait_until 和 boost::asio::streambuf