【问题标题】:ConnectNamedPipe and asio overlappped ptrConnectNamedPipe 和 asio 重叠 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对象

标签: c++ windows boost-asio named-pipes


【解决方案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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-24
    • 2021-04-06
    • 1970-01-01
    • 2013-07-19
    • 1970-01-01
    相关资源
    最近更新 更多