首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使客户端在c++中将数据写入管道之前检查服务器是否完成从管道中读取的操作

如何使客户端在c++中将数据写入管道之前检查服务器是否完成从管道中读取的操作
EN

Stack Overflow用户
提问于 2018-07-02 09:00:48
回答 1查看 950关注 0票数 0

我需要我的客户首先检查服务器是否正在从管道中读取数据,如果是,则等待服务器完成,否则将数据写入管道。如果我在我的示例客户端程序中不使用睡眠命令,那么Server就不会正确地读取消息。我从文档中发现了这个问题的原因,它说:

此缓冲区在读取操作期间必须保持有效。在读取操作完成之前,调用方不能使用此缓冲区。

但在读取操作完成之前,它不会指定如何阻止客户端。

服务器代码:

代码语言:javascript
运行
复制
#include<stdio.h>
#include<windows.h>
#include<iostream>
using namespace std;
int main(void)
{
    HANDLE hPipe;
    char buffer[1024];
    DWORD dwRead;


hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
                        PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE,
                        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
                        1,
                        1024 * 16,
                        1024 * 16,
                        NMPWAIT_USE_DEFAULT_WAIT,
                        NULL);
while (hPipe != INVALID_HANDLE_VALUE)
{
    if (ConnectNamedPipe(hPipe, NULL) != FALSE)   // wait for someone to connect to the pipe
    {
        while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
        {
            /* add terminating zero */
            buffer[dwRead] = '\0';

            /* do something with data in buffer */
            printf("%s", buffer);
        }
    }

    DisconnectNamedPipe(hPipe);
}

return 0;

}

客户代码:

代码语言:javascript
运行
复制
#include<stdio.h>
#include<windows.h>
#include<iostream>
#include<stdlib.h> 
using namespace std;
void fun()
{
     HANDLE hPipe;
    DWORD dwWritten;


    hPipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), 
                       GENERIC_WRITE, 
                       0,
                       NULL,
                       OPEN_EXISTING,
                       0,
                       NULL);
    if (hPipe != INVALID_HANDLE_VALUE)
    {
        WriteFile(hPipe,
                  "Hello Pipe",
                  11,   // = length of string + terminating '\0' !!!
                  &dwWritten,
                  NULL);

        CloseHandle(hPipe);
    }

}
int main(void)
{
   int a = 5;
   cout<<a;
   for(int i = 0; i<a; i++)
   {
    fun();
    Sleep(2000);
   }

    return (0);
}

这只是一个示例程序,实际上我的客户端是一个很大的应用程序,它有很多功能,我不想对它做任何重大更改。每当某个特定函数被触发时,它都应该将数据传递给服务器。数据类型是一个结构。在服务器中接收数据后,我想将该数据写入文本文件(将其转换为json格式)。

那么,在将数据写入管道之前,如何让我的客户端检查服务器是否完成了从管道读取数据?客户端不应该永远等待服务器,因为它会影响我的客户端应用程序。它应该等待指定的时间间隔。另外,要传递结构,我应该使用字节模式还是消息模式?

EN

回答 1

Stack Overflow用户

发布于 2018-07-02 10:54:20

下一行服务器代码中的主要错误

代码语言:javascript
运行
复制
if (ConnectNamedPipe(hPipe, NULL) != FALSE)

在这里,我们假设如果ConnectNamedPipe返回FALSE,它将失败。但是,即使对于同步管道句柄也不是这样:

否则,ConnectNamedPipe返回零,如果上一个客户端关闭了句柄,GetLastError返回ERROR_NO_DATA,如果没有关闭句柄,则返回ERROR_PIPE_CONNECTED

客户端可以在CreateFile服务器调用CreateNamedPipeW之后连接(调用CreateNamedPipeW),而在调用ConnectNamedPipe之前连接。在这种情况下,驱动程序可以在FSCTL_PIPE_LISTEN (ConnectNamedPipe)请求上返回2状态:

  1. 如果客户端已经连接(在STATUS_PIPE_CONNECTED之前)但尚未关闭自己的句柄,则为ERROR_PIPE_CONNECTED (翻译为ERROR_PIPE_CONNECTED)
  2. STATUS_PIPE_CLOSING (转换为ERROR_NO_DATA)客户机关闭了它的句柄。但在此之前,他可以调用WriteFile,管道中的一些数据也确实存在。

还可以在调用NMPWAIT_USE_DEFAULT_WAIT中使用CreateNamedPipeW -这里必须是实际的超时。这个常量用于调用WaitNamedPipeW

下一段代码可以测试同步管道客户机/服务器。(当然,更好地使用异步i/o)

代码语言:javascript
运行
复制
ULONG WINAPI ct(void* name)
{
    if (WaitNamedPipeW((PCWSTR)name, NMPWAIT_USE_DEFAULT_WAIT))
    {
        MessageBoxW(0, 0, L"client delay #1", 0);// for debug

        HANDLE hPipe = CreateFileW((PCWSTR)name, 
            GENERIC_WRITE, 
            0,
            NULL,
            OPEN_EXISTING,
            0,
            NULL);

        if (hPipe != INVALID_HANDLE_VALUE)
        {
            static WCHAR str[] = L"Hello Pipe";

            DWORD dwWritten;

            WriteFile(hPipe, str,
                sizeof(str),
                &dwWritten,
                NULL);

            MessageBoxW(0, 0, L"client delay #2", 0);// for debug

            CloseHandle(hPipe);
        }
    }

    return GetLastError();
}

void sc()
{
    char buffer[1024];

    static WCHAR name[] = L"\\\\.\\pipe\\Pipe";

    HANDLE hPipe = CreateNamedPipeW(name,
        PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE,
        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
        1,
        1024 * 16,
        1024 * 16,
        INFINITE,
        NULL);

    if (hPipe != INVALID_HANDLE_VALUE)
    {
        int n = 2;
        do
        {
            CloseHandle(CreateThread(0, 0, ct, name, 0, 0));
            MessageBoxW(0, 0, L"Server delay", 0);// for debug

            switch (ConnectNamedPipe(hPipe, NULL) ? NOERROR : GetLastError())
            {
            case NOERROR:
            case ERROR_PIPE_CONNECTED: // STATUS_PIPE_CONNECTED
            case ERROR_NO_DATA: // STATUS_PIPE_CLOSING

                DWORD dwRead;
                while (ReadFile(hPipe, buffer, sizeof(buffer), &dwRead, NULL))
                {
                    /* do something with data in buffer */
                    printf("%.*S", dwRead, buffer);
                }

                DisconnectNamedPipe(hPipe);
                break;
            }
        } while (--n);

        CloseHandle(hPipe);
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51132447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档