管道服务器不是每秒发送文本

PipeServer not sending text every second

本文关键字:文本 服务器 管道      更新时间:2023-10-16

这是第一个应用程序中的"PipeServer":

  // Open Pipe and wait until ControlProgram is connecting
Pipe.Out = INVALID_HANDLE_VALUE;
const wchar_t *data = L"*** Hello Pipe World ***";
DWORD numBytesWritten = 0;
DWORD timerinit = GetTickCount();;
while (1)
{
    DWORD timer = GetTickCount();
    if ((timer - timerinit) > 1000)
    {
        timerinit = timer;
        if (ConnectNamedPipe(Pipe.Out, NULL))
        {
            WriteFile(
                Pipe.Out, // handle to our outbound pipe
                data, // data to send
                wcslen(data) * sizeof(wchar_t), // length of data to send (bytes)
                &numBytesWritten, // will store actual amount of data sent
                NULL // not using overlapped IO
            );
        }
        else
        {
            CloseHandle(Pipe.Out);
            Pipe.Out = INVALID_HANDLE_VALUE;
            do
            {
              Pipe.Out = CreateNamedPipeW(
                L"\\.\pipe\mypipe", // name of the pipe
                PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
                PIPE_TYPE_BYTE, // send data as a byte stream
                1, // only allow 1 instance of this pipe
                0, // no outbound buffer
                0, // no inbound buffer
                0, // use default wait time
                NULL // use default security attributes
                );
            }
            while (Pipe.Out == INVALID_HANDLE_VALUE);
        }
    }
}

这是"PipeClient"应用程序:

///// CLIENT PROGRAM /////
#include <iostream>
#include <windows.h>
using namespace std;
int main(int argc, const char **argv)
{
    wcout << "Connecting to pipe..." << endl;
    // Open the named pipe
    // Most of these parameters aren't very relevant for pipes.
    HANDLE pipe = CreateFileW(
                      L"\\.\pipe\mypipe",
                      GENERIC_READ, // only need read access
                      FILE_SHARE_READ | FILE_SHARE_WRITE,
                      NULL,
                      OPEN_ALWAYS,
                      FILE_ATTRIBUTE_NORMAL,
                      NULL
                  );
    if (pipe == INVALID_HANDLE_VALUE)
    {
        wcout << "Failed to connect to pipe." << endl;
        // look up error code here using GetLastError()
        system("pause");
        return 1;
    }
    wcout << "Reading data from pipe..." << endl;
    while (1)
    {
        // The read operation will block until there is data to read
        wchar_t buffer[128];
        DWORD numBytesRead = 0;
        BOOL result = ReadFile(
                          pipe,
                          buffer, // the data from the pipe will be put here
                          127 * sizeof(wchar_t), // number of bytes allocated
                          &numBytesRead, // this will store number of bytes actually read
                          NULL // not using overlapped IO
                      );
        if (result)
        {
            buffer[numBytesRead / sizeof(wchar_t)] = ''; // null terminate the string
            wcout << "Number of bytes read: " << numBytesRead << endl;
            wcout << "Message: " << buffer << endl;
            FlushFileBuffers(pipe);
        }
        else
        {
            wcout << "Failed to read data from the pipe." << endl;
            wcout << result << endl;
            CloseHandle(pipe);
            break;
        }
    }
    // Close our pipe handle
    wcout << "Done." << endl;
    system("pause");
    return 0;
}

服务器应等待客户端连接,然后每 1 秒发送一次定义的消息。

客户端应该能够随时启动/重新启动。

但是每当我启动客户端时,它都会收到一次消息,然后在从管道读取时退出并出错。

结果返回 0。

更新(对于那些想知道它现在如何工作的人)

这是"更新的"PipeServer 代码:

  // Open Pipe and wait until ControlProgram is connecting
    Pipe.Out = INVALID_HANDLE_VALUE;
    DWORD numBytesWritten = 0;
    DWORD timerinit = GetTickCount();
    bool connected = false;
    bool writesucc = false;
    bool initial = true;
    while (1)
    {
        DWORD timer = GetTickCount();
        wchar_t data[100];
        if (!initial)
        {
            swprintf_s(data, 100, L"Time: %d", timer); // use L"" prefix for wide chars
        }
        else
        {
            swprintf_s(data, 100, L"Welcome from your Pipe Server"); // use L"" prefix for wide chars
        }
        if ((timer - timerinit) > 1000)
        {
            timerinit = timer;
            if (!connected)
            {
                connected = ConnectNamedPipe(Pipe.Out, NULL);
            }
            if (connected)
            {
                writesucc = WriteFile(
                    Pipe.Out, // handle to our outbound pipe
                    data, // data to send
                    wcslen(data) * sizeof(wchar_t), // length of data to send (bytes)
                    &numBytesWritten, // will store actual amount of data sent
                    NULL // not using overlapped IO
                );
                if (writesucc) initial = false;
            }
            if ((!writesucc) || (Pipe.Out == INVALID_HANDLE_VALUE) || (!connected))
            {
                initial = true;
                CloseHandle(Pipe.Out);
                Pipe.Out = INVALID_HANDLE_VALUE;
                do
                {
                  Pipe.Out = CreateNamedPipeW(
                    L"\\.\pipe\mypipe", // name of the pipe
                    PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
                    PIPE_TYPE_BYTE, // send data as a byte stream
                    1, // only allow 1 instance of this pipe
                    0, // no outbound buffer
                    0, // no inbound buffer
                    0, // use default wait time
                    NULL // use default security attributes
                    );
                }
                while (Pipe.Out == INVALID_HANDLE_VALUE);
            }
        }
    }

您的客户端失败,因为服务器每秒调用一次ConnectNamedPipe(),然后关闭连接,如果失败ConnectNamedPipe()因为已经连接了一个客户端,而您一次只允许连接一个客户端。 这在ConnectNamedPipe()文档中有说明:

命名管道服务器进程可以将 ConnectNamedPipe 与新创建的管道实例一起使用。它还可用于以前连接到另一个客户端进程的实例;在这种情况下,服务器进程必须首先调用 DisconnectNamedPipe 函数以断开句柄与上一个客户端的连接,然后才能将句柄重新连接到新客户端。否则,ConnectNamedPipe 返回零,如果上一个客户端已关闭其句柄,则返回ERROR_NO_DATA,如果尚未关闭其句柄,则返回ERROR_PIPE_CONNECTED。

你只写一次你的消息 - 当ConnectNamedPipe()成功地创建一个新连接时。 在那之后,您不会循环写入,您的下一次迭代会再次调用ConnectNamedPipe()并失败。

您没有检查来自GetLastError()的任何错误代码,否则您会在阅读文档以了解错误代码的含义后注意到这种情况。

尝试更多类似的东西:

const wchar_t *data = L"*** Hello Pipe World ***";
DWORD numBytesWritten;
Pipe.Out = CreateNamedPipeW(
    L"\\.\pipe\mypipe", // name of the pipe
    PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
    PIPE_TYPE_BYTE, // send data as a byte stream
    1, // only allow 1 instance of this pipe
    0, // no outbound buffer
    0, // no inbound buffer
    0, // use default wait time
    NULL // use default security attributes
    );
if (Pipe.Out == INVALID_HANDLE_VALUE)
{
    // error creating pipe
}
else
{
    while (should wait for a client to connect)
    {
        if (!ConnectNamedPipe(Pipe.Out, NULL))
        {
            // if ERROR_PIPE_CONNECTED then a client is actually connected!
            if (GetLastError() != ERROR_PIPE_CONNECTED)
            {
                // error connecting a client
                break;
            }
        }
        DWORD timerinit = GetTickCount();
        while (should write to the client)
        {
            DWORD timer = GetTickCount();
            // GetTickCount() wraps back to 0 every 49.7 days, so account for that...
            DWORD elapsed = (timer >= timerinit) ? (timer - timerinit) : ((MAXDWORD - timerinit) + timer);
            if (elapsed >= 1000)
            {
                timerinit = timer;
                if (!WriteFile(
                    Pipe.Out, // handle to our outbound pipe
                    data, // data to send
                    wcslen(data) * sizeof(wchar_t), // length of data to send (bytes)
                    &numBytesWritten, // will store actual amount of data sent
                    NULL // not using overlapped IO
                )
                {
                    // error writing to client
                    break;
                }
            }
        }
        DisconnectNamedPipe(Pipe.Out);
    }
    CloseHandle(Pipe.Out);
}