如何使Windows Pipe在处理完成时添加EOF

时间:2019-07-15 14:48:01

标签: c windows winapi pipe

我正在Windows上模拟循环管道的递归C函数。

到目前为止,这是我的功能:


static BOOL execute_in_pipe(char (*cmdline)[1024], char *env, int index,
    int pipe_length, STARTUPINFO *old_suinfo, HANDLE proc_handles[])
{
    //Create new startup info
    STARTUPINFO suinfo;
    memset(&suinfo, 0, sizeof(suinfo));
    suinfo.cb = sizeof(suinfo);

    //Create new process info
    PROCESS_INFORMATION pinfo;

    //Make pipe
    HANDLE pipe_out_rd, pipe_out_wr;
    if(index > 0) {
        HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

        SECURITY_ATTRIBUTES sa; 
        sa.nLength = sizeof(SECURITY_ATTRIBUTES); 
        sa.bInheritHandle = TRUE; 
        sa.lpSecurityDescriptor = NULL; 

        if (! CreatePipe(&pipe_out_rd, &pipe_out_wr, &sa, 0))
        {
            CloseHandle(pipe_out_wr);
            CloseHandle(pipe_out_rd);
            //res.tag = NATIVE_ERR_PIPE_FAILED;
            //return res;
        }

        //Set output of last process to write handle
        if((*old_suinfo).hStdInput == 0) {
            (*old_suinfo).hStdInput = hIn;
        }
        (*old_suinfo).hStdOutput = pipe_out_wr;
        (*old_suinfo).dwFlags = STARTF_USESTDHANDLES;

        //Set input of this process to read handle
        suinfo.hStdInput = pipe_out_rd;
        if(index >= pipe_length-1) {
            suinfo.hStdOutput = hOut;
        }
        suinfo.dwFlags = STARTF_USESTDHANDLES;
    }

    BOOL result = TRUE;
    if(index < pipe_length-1) {
        result = execute_in_pipe(cmdline, env, index+1, pipe_length, &suinfo, proc_handles);
    }

    //Return whether creating process succeeds
    if(!CreateProcess(NULL, cmdline[index], NULL, NULL,
        (pipe_length>1), 0, env, NULL, &suinfo, &pinfo))
    {
        return FALSE;
    }

    CloseHandle(pinfo.hThread);

    proc_handles[index] = pinfo.hProcess;

    return result;
}

我制作了两个c程序来测试管道:

seed.c

#include <stdio.h>

int main() {
   printf("Hello");
}

append.c

#include <stdio.h>
#include <string.h>

int main() {
   char str[200];
   scanf( "%s", str );

   printf("%s World!", str);
}

然后我使用以下命令调用了这些函数

    STARTUPINFO suinfo;
    HANDLE proc_handles[2];
    printf("Starting\n");
    char cmdline[2][1024] = {"seed.exe", "append.exe"};

    execute_in_pipe(cmdline, 0, 0, 2, &suinfo, proc_handles);

    WaitForMultipleObjects(2, proc_handles, TRUE, INFINITE);

调用此函数时,控制台将打印出“正在启动”,然后永远等待...

我很确定原因是scanf试图读取FULL LINE(最多是某种分隔符)。当我将seed.c更新为`printf(“ Hello \ n”)时,它运行正常。

是的,这只是一条规则吗?所有管道处理都应使用换行符吗?

好吧,在命令提示符中调用seed.exe | append.exe很有效!即使没有换行符!我的代码丢失了什么?

编辑: 正如某些人所指出的,当所有管道都关闭时,Unix管道会进入“流结束”状态(不是我最初认为的EOF)。在测试Unix管道系统时,不会出现此问题,因此流结束就像分隔符一样。 Windows是否做类似的事情?如果是这样,我是否需要关闭某些内容以使其结束流?

2 个答案:

答案 0 :(得分:1)

您应该使用命名管道而不是未命名管道来进行I / O重定向。关闭服务器的管道句柄后,客户端上的scanf()会知道它并停止等待换行符。

下面的代码是用pascal编写的,但并不难理解。

const
  BUFSIZE:integer = 512;
  Pipename:String = '\\.\pipe\devcpp_run';

InputWrite := CreateNamedPipe(
      pAnsiChar(Pipename),             // pipe name
      PIPE_ACCESS_OUTBOUND,       // read/write access
      PIPE_TYPE_BYTE or       // message type pipe
      PIPE_READMODE_BYTE or   // message-read mode
      PIPE_WAIT,                // blocking mode
      PIPE_UNLIMITED_INSTANCES, // max. instances
      BUFSIZE,                  // output buffer size
      BUFSIZE,                  // input buffer size
      0,                        // client time-out
      nil);                    // default security attribute
if InputWrite = INVALID_HANDLE_VALUE then begin
      Exit;
end;
InputRead := CreateFile(
     PAnsiChar(Pipename),   // pipe name
     GENERIC_READ,
     0,              // no sharing
     @sa,           // default security attributes
     OPEN_EXISTING,  // opens existing pipe
     0,              // default attributes
     0);
if InputRead = INVALID_HANDLE_VALUE then begin
  Exit;
end;
StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESTDHANDLES;
StartupInfo.hStdInput := InputRead;
StartupInfo.hStdOutput := 7; // Undocumented Handle of Console Output
StartupInfo.hStdError := 11; // Undocumented Handle of Console Error Output
end;

答案 1 :(得分:0)

scanf正在等待“结束”条件并挂起。这就是问题。

以下是一种变通方法,您可以查看是否有帮助:

像这样编辑append.c

#include <stdio.h>
#include <string.h>
#include <windows.h>

#define BUFFER_SIZE  200

int main()
{
    DWORD dwRead = 0;
    char str[BUFFER_SIZE];

    HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
    for (;;)
    {
        BOOL bSuccess = ReadFile(hStdIn, str, BUFFER_SIZE, &dwRead, NULL);
        if (bSuccess && dwRead > 0) break;
    }
    for(DWORD i = 0; i< dwRead; i++)
        printf("%c", str[i]);

    printf(" World!");
}

使用ReadFile而不是scanf来读取标准输入流。