本文介绍了ConnectNamedPipe和ASIO重叠PTR的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've named pipe server which is written using boost asio. Server creates named pipe and calls ConnectNamedPipe passing asio overlapped ptr to it. The problem is that completion handler passed to asio overlapped is never called, that is calling CreateFile on client side won't trigger completion handler passed to ConnectNamedPipe. What am I doing wrong?

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

Here is full listing of both client and server:

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

推荐答案

发现了问题.我没有在服务器部分将管道与IOCP本身关联.可以通过在调用ConnectNamedPipe之前将CreateNamedPipeA返回的管道本机句柄包装到boost::asio::windows::stream_handle中来完成.

Found the issue. I've not associated pipe with IOCP itself in server part. It can be done by wrapping pipe native handle returned by CreateNamedPipeA into boost::asio::windows::stream_handle just before calling ConnectNamedPipe.

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

这篇关于ConnectNamedPipe和ASIO重叠PTR的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 16:47