uv_start_read на windows клиент именованного канала ждет, пока сервер не закроет свой канал и не выдаст EOF - PullRequest
0 голосов
/ 11 февраля 2020

У меня есть две программы, одна из которых я написал и работает как конвейерный сервер и использует порты завершения io. другой не написан мной, но это открытый исходный код, и он интенсивно использует libuv для своей асинхронной обработки c.

Теперь я хочу отредактировать эту программу, чтобы добавить функциональность канала через libuv и иметь возможность связаться с сервером.

Я могу подключиться к серверу, используя uv_pipe_connect, и я получаю вызов обратного вызова подключения, затем я начинаю читать с uv_read_start, который возвращает 0 (без ошибок), поэтому я ожидаю обратного вызова распределения и callback read read запускается, когда сервер пишет клиенту.

однако, когда сервер записывает несколько байтов, и я получаю уведомление через 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);
}

1 Ответ

0 голосов
/ 11 февраля 2020

Мне пришлось установить флаг ip c на 0 в uv_pipe_init и установить данные m_pipe, чтобы они указывали на мой PipeClient класс.

отсюда: https://github.com/libuv/libuv/blob/v1.x/src/win/pipe.c

Я видел, что запись чтения канала - это не обычная запись чтения iocp, если установлен флаг ip c, вместо этого использовать другие методы, которые мне не нужны

...