c - Windows 命名管道客户端上的 uv_start_read 等待服务器关闭其管道并导致 EOF

标签 c named-pipes libuv

我有两个程序,其中一个是我编写的,用作管道服务器并使用 io 完成端口。 另一个不是我写的,但它是开源的,并且大量使用 libuv 进行异步处理。

现在我想编辑这个程序以通过 libuv 添加管道功能并能够联系服务器。

我可以使用 uv_pipe_connect 连接到服务器,并触发连接回调,然后我开始使用 uv_read_start 进行读取,它返回 0(没有错误),所以我期望一旦服务器写入客户端,分配回调和读取回调就会被触发。

但是,当服务器写入一些字节并且我通过 iocp 收到已写入一定量字节的通知时,客户端不会收到任何内容,也不会调用任何回调。关闭服务器进程时,会调用读取回调,并显示错误 EOF

这是我正在使用的 libuv 相关代码:

class IPipeListener;

class PipeClient
{

public:

    PipeClient(IPipeListener* listener, const std::string& pipe_name);

    ~PipeClient();

    void stop();

private:

    static void onAllocBuff(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);

    static void onConnect(uv_connect_t *connect_req, int result);

    static void onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);

    static void onWrite(uv_write_t* req, int result);

    // a pod structure used to read and write data 
    PipeCommand command;
    IPipeListener* m_listener = nullptr;
    uv_pipe_t m_pipe;
    uv_connect_t m_connect;
    uv_read_t read_req;
    uv_write_t write_req;
};

PipeClient::PipeClient(IPipeListener* listener, const std::string& pipe_name)
{
    if (!listener || pipe_name.empty())
        return;
    m_listener = listener;
    uv_pipe_init(uv_default_loop(), &m_pipe, 1);
    m_connect.data = this;
    write_req.data = this;
    read_req.data = this;
    uv_pipe_connect(&m_connect, &m_pipe, pipe_name.c_str(), onConnect);
}

void PipeClient::onAllocBuff(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
    MessageBoxA(0, "onAllocBuff", "onAllocBuff", 0);
    auto pipe = static_cast<PipeClient*>(handle->data);
    buf->base = reinterpret_cast<char*>(&pipe->command);
    buf->len = sizeof(pipe->command);
}

void PipeClient::onConnect(uv_connect_t* connect_req, int result)
{
    MessageBoxA(0, "onConnect", "onConnect", 0);
    auto pipe = static_cast<PipeClient*>(connect_req->data);
    if (result < 0)
    {
        pipe->command.code = PipeCommand::OpCode::Error;
        pipe->m_listener->onPipeCommand(pipe->command);
        return;
    }
    MessageBoxA(0, "starting read", "notify", 0);
    int r = uv_read_start(connect_req->handle, onAllocBuff, onRead);
    if (r != 0)
    {
        std::string err_msg = "failed to start reading with error : ";
        err_msg += uv_err_name(r);
        MessageBoxA(0, err_msg.c_str(), "error", 0);
    }
}

void PipeClient::onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
{
    MessageBoxA(0, "onRead", "onRead", 0);
    auto pipe = static_cast<PipeClient*>(stream->data);
    uv_read_stop(stream);
    if (nread < 0)
    {
        std::string err_msg = "failed to read with error : ";
        err_msg += uv_err_name(nread);
        MessageBoxA(0, err_msg.c_str(), "error", 0);
        pipe->command.code = PipeCommand::OpCode::Error;
        pipe->m_listener->onPipeCommand(pipe->command);
        return;
    }

    pipe->m_listener->onPipeCommand(pipe->command);
    uv_buf_t write_buff;
    write_buff.base = reinterpret_cast<char*>(&pipe->command);
    write_buff.len = sizeof(pipe->command);
    uv_write(&pipe->write_req,
        stream, &write_buff, 1, onWrite);
}

最佳答案

我必须在 uv_pipe_init 中将 ipc 标志设置为 0,并将 m_pipe 的数据设置为指向我的 PipeClient 类。

从这里开始: https://github.com/libuv/libuv/blob/v1.x/src/win/pipe.c

我看到如果设置了 ipc 标志,管道读取写入不是普通的 iocp 读取写入,而是采用我不想要的另一种方法

关于c - Windows 命名管道客户端上的 uv_start_read 等待服务器关闭其管道并导致 EOF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60167842/

相关文章:

c - GCC 不保存/恢复函数调用的保留寄存器

c - glibc malloc 保护字节包装器

c++ - 有没有办法检查变量是否在编译时声明?

wcf - 除了 RESTful HTTP 之外,我还应该支持其他任何东西吗?

Node.js:为什么空闲和准备阶段仅在内部使用?

c - ANSI C 多平台编译器和 GUI

c++ - 如何在没有数据损坏风险的情况下序列化对象?

c - FIFO - 从顶层进程读取,从底层进程写入

c - libuv 和 uv_try_write : why multiple buffers?

c++ - libuv - 在没有多线程的情况下限制空闲事件的回调率而不阻塞线程