无法从匿名管道读取

时间:2015-02-05 14:14:15

标签: c++ c windows winapi pipe

我开始研究Windows中的匿名管道并遇到了问题。

程序应该创建一个子进程来处理给定的命令。但是在子进程工作之前我无法读取管道。

这是程序

#define _CRT_SECURE_NO_DEPRECATE
#include "windows.h"
#include "cstdio"
#include "tchar.h"
#include "io.h"
#include "conio.h" 
#include "cstring"

static const int bufSize = 20;

int main() {
    STARTUPINFO si;
    PROCESS_INFORMATION  pi;
    LPTSTR szCmdline = _tcsdup(TEXT("Project2\\Release\\command_handler.exe"));
    HANDLE writePipe, readPipe, writePipeInput, readPipeInput;
    SECURITY_ATTRIBUTES sa;
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    if(!CreatePipe(&readPipe, &writePipe, &sa, 0) || !CreatePipe(&readPipeInput, &writePipeInput, &sa, 0))
    {
        printf("ERROR: cannot create pipe\n");
        system("pause");
        exit(1);
    }
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdOutput = writePipe;
    si.hStdInput = readPipeInput;
    DWORD dwByteRead, dwByteWrite;
    if(!CreateProcess(0, szCmdline, 0, 0, TRUE, CREATE_NO_WINDOW, 0, 0, &si, &pi)) {
        printf("ERROR: cannot create process\n");
        system("pause");
        exit(2);
    }
    CloseHandle(writePipe);
    CloseHandle(readPipeInput);
    printf("Procces ready!\n");

    TQueue <int> q;
    TQueue <int> tmp;
    char c;
    char s[bufSize];
    int value;
    for ( ; ; ) {
        int i;
        for(i = 0;i < bufSize && (s[i] = getchar()) != '\n';++i);
        WriteFile(writePipeInput,s,i + 1,&dwByteWrite,NULL);

        ReadFile(readPipe, &c, (int)1, &dwByteRead, NULL);
        printf("Get : '%c'\n",c);
        switch (c) {
            case '+':
                ReadFile(readPipe, &value, sizeof(int), &dwByteRead, NULL);
                printf("%d\n",value);
                q.push(value);
                printf("OK\n");
                break;
            case '-':
                if (!q.empty()) {
                    q.pop();
                }
                printf("OK\n");
                break;
            case 'f':
                if (!q.empty()) {
                    printf("%d\nOK\n",q.firstEl());
                } else {
                    printf("Queue is empty\nOK\n");
                }
                break;
            case 'p':
                if (q.empty()) {
                    printf("empty");
                }
                while (!q.empty()) {
                    tmp.push(q.firstEl());
                    printf("%d ",q.firstEl());
                    q.pop();
                }
                printf("\nOK\n");
                while (!tmp.empty()) {
                    q.push(tmp.firstEl());
                    tmp.pop();
                }
                break;
            case 'e':
                printf("%s\nOK\n",q.empty()?"yes!":"no");
                break;
            case 'q':
                break;
            case '?':
                printf("ERROR: undefined command\n");
                break;
            default:
                printf("Fatal error: wrong symbol from hadeler '%c'\n",c);
                //system("pause");
                //exit(3);
        }
        if (c == 'q') break;
    }
    CloseHandle(readPipe);
    CloseHandle(writePipeInput);
    printf("Exited normaly\n");
    system("pause");
}

这是处理程序

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

static const int sz = 10;

char read_cmd(char *s) {
    char c = getchar();
    int i;
    for (i = 0;(i < sz) && (c != ' ') && (c != '\n');i++) {
        s[i] = c;
        c = getchar();
//      printf("%c",s[i]);
    }
    s[i] = '\0';
    return c;
}

char correct(char res) {
    if (res != '\n') {
        while (getchar() != '\n');
        return 0;
    }
    return 1;
}

int main() {
    char s[sz + 1];
    char c, res;
    int val = 0;
    for ( ; ; ) {
        res = read_cmd(s);
        if (strcmp(s,"add") == 0) {
            val = 0;
            while ((c = getchar()) >= '0' && c <= '9') {
                val = val * 10 + c - '0';
            }
            res = c;
            c = '+';
        }else if (strcmp(s,"pop") == 0) {
            c = '-';
        }else if (strcmp(s,"first") == 0) {
            c = 'f';
        }else if (strcmp(s,"print") == 0) {
            c = 'p';
        }else if (strcmp(s,"empty") == 0) {
            c = 'e';
        }else if (strcmp(s,"help") == 0) {
            c = 'h';
        }else if (strcmp(s,"quit") == 0) {
            c = 'q';
        }else {
            c = '?';
        }
        if (!correct(res)) c = '?';
        printf("%c",c);
        if (c == 'q') break;
        if (c == '+') printf("%d",val);
    }
    return 0;
}

所以,如果我运行它并立即输入&#34;退出&#34;它可以工作,否则在尝试从输出管道获取结果时会停止。

为什么会这样?

提前感谢您的回复。

1 个答案:

答案 0 :(得分:1)

我重新编写了程序并且有效。老实说,我不知道有没有正确的。这是一个工作版本:

#define _CRT_SECURE_NO_DEPRECATE

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

#define BUFSIZE 256

template <class T> class TQueue {
private:
    class TQueEl {
    public:
        T value;
        TQueEl *next, *prev;
    };
    TQueEl *first, *last;
    int size;
public:
    int& operator = (TQueue <T>& b){
        while (!empty ()) {
            pop ();
        }
        while (!b.empty ()) {
            push(b.firstEl ());
            b.pop ();
        }
    }
    TQueue () {
        size = 0;
        first = last = nullptr;
    }
    void push (T val) {
        if (size == 0) {
            first = last = new TQueEl;
            first -> next = first -> prev = nullptr;
            first -> value = val;
        } else {
            last -> next = new TQueEl;
            last -> next -> prev = last;
            last = last -> next;
            last -> next = nullptr;
            last -> value = val;
        }
        size++;
    }
    T firstEl () {
        return first -> value;
    }
    void pop () {
        TQueEl *tmp=first;
        if (size == 1) {
            first = last = nullptr;
        } 
        else if ( empty() ) {
            // error("pop of empty queue");
        }
        else {
            first = first -> next;
            first -> prev = nullptr;
        }
        size--;
        delete tmp;
    }
    bool empty () {
        return !size;
    }
    ~TQueue () {
        TQueEl *tmp;
        while (first != nullptr) {
            tmp = first;
            first = first -> next;
            delete tmp;
        }
    }
};

DWORD WINAPI rerout(LPVOID params) {
    DWORD dwByteWrite, dwByteRead;
    char buffer[BUFSIZE];
    HANDLE hParentStdIn = GetStdHandle(STD_INPUT_HANDLE);
    HANDLE childInput = (HANDLE) params;
    for ( ; ; ) {
        ReadFile(hParentStdIn, buffer, BUFSIZE, &dwByteRead, NULL);
        WriteFile(childInput, buffer, dwByteRead, &dwByteWrite, NULL);
    }
    return 0;
}

int main() { 
    HANDLE childInputRd = NULL;
    HANDLE childInputWr = NULL;
    HANDLE childOutputRd = NULL;
    HANDLE childOutputWr = NULL;
    SECURITY_ATTRIBUTES sa; 

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

    if ( ! CreatePipe(&childOutputRd, &childOutputWr, &sa, 0) ) {
        printf("Fatal error: cannot create child output pipe\n");
        system("pause");
        exit(1);
    }
    if (! CreatePipe(&childInputRd, &childInputWr, &sa, 0)) {
        printf("Fatal error: cannot create child input pipe\n");
        system("pause");
        exit(2);
    }
    TCHAR szCmdline[]=TEXT("Project2\\Release\\command_handler.exe");
    PROCESS_INFORMATION pi; 
    STARTUPINFO si;

    ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );

    ZeroMemory( &si, sizeof(STARTUPINFO) );
    si.cb = sizeof(STARTUPINFO); 
    si.hStdError = childOutputWr;
    si.hStdOutput = childOutputWr;
    si.hStdInput = childInputRd;
    si.dwFlags = STARTF_USESTDHANDLES;

    if ( !CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) ) {
        printf("Fatal error: cannot create child process\n");
        system("pause");
        exit(3);
    }
    else {
        CloseHandle(childInputRd);
        CloseHandle(childOutputWr);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }

    DWORD reroutThreadID;
    HANDLE inputRerouting = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)rerout,(LPVOID) childInputWr,0 , &reroutThreadID);
    if (inputRerouting == NULL) {
        printf("Fatal error: cannot create thread\n");
        system("pause");
        exit (4);
    }

    TQueue <int> q;
    TQueue <int> tmp; 
    DWORD dwRead; 
    CHAR c;
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    for (;;) {
        ReadFile( childOutputRd, &c, sizeof(char), &dwRead, NULL);
        switch (c) {
            case '+':
                int value;
                ReadFile( childOutputRd, &value, sizeof(int), &dwRead, NULL);
                q.push(value);
                printf("OK\n");
                break;
            case '-':
                if (!q.empty()) {
                    q.pop();
                    printf("OK\n");
                }
                else {
                    printf("Queue is empty!\n");
                }
                break;
            case 'f':
                if (!q.empty()) {
                    printf("%d\n",q.firstEl());
                } else {
                    printf("Queue is empty!\n");
                }
                break;
            case 'p':
                printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n");
                if (q.empty()) {
                    printf("empty");
                }
                while (!q.empty()) {
                    tmp.push(q.firstEl());
                    printf("%d ",q.firstEl());
                    q.pop();
                }
                while (!tmp.empty()) {
                    q.push(tmp.firstEl());
                    tmp.pop();
                }
                printf("\n\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\nOK\n");
                break;
            case 'e':
                printf("%s\n",q.empty()?"YES":"NO");
                break;
            case 'q':
                break;
            case '?':
                printf("ERROR: undefined command\n");
                break;
            default:
                printf("Fatal error: wrong symbol from hadeler '%c'\n",c);
                system("pause");
                exit(5);
        }
        if (c == 'q') break;
    }
    CloseHandle(inputRerouting);
    CloseHandle(childInputWr);
    CloseHandle(childOutputRd);
    system("pause");
    return 0; 
}

处理程序:

#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#include <stdio.h>

#define BUFSIZE 5 

HANDLE hStdin, hStdout;
DWORD dwRead, dwWritten; 

void readCmd(char* s) {
    ReadFile(hStdin, s, 1, &dwRead, NULL);
    int i;
    for (i = 0;(i < BUFSIZE) && (s[i] != ' ') && (s[i] != '\n') && (s[i] != '\r');i++) {
        ReadFile(hStdin, s + i + 1, 1, &dwRead, NULL);
    }
    s[i] = '\0';
}

bool correct() {
    char c;
    ReadFile(hStdin, &c, sizeof(char), &dwRead, NULL);
    if (c != '\n') {
        while (c != '\n') ReadFile(hStdin, &c, sizeof(char), &dwRead, NULL);
        return 0;
    }
    return 1;
}

int main() { 
    hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
    hStdin = GetStdHandle(STD_INPUT_HANDLE); 
    if ( (hStdout == INVALID_HANDLE_VALUE) || (hStdin == INVALID_HANDLE_VALUE) ) {
        ExitProcess(1); 
    } 
    int val;
    char s[BUFSIZE + 1];
    char c,digit;
    for (;;) { 
        readCmd(s);
        if (strcmp(s,"add") == 0) {
            val = 0;
            ReadFile(hStdin, &digit, 1, &dwRead, NULL);
            if (digit == '\n') {
                c = '?';
                WriteFile(hStdout,&c,sizeof(char),&dwRead,NULL);
                continue;
            }
            else if (digit < '0' || digit > '9') {
                c = '?';
            }
            else {
                c = '+';
            }
            while (digit >= '0' && digit <= '9') {
                val = val * 10 + digit - '0';
                ReadFile(hStdin, &digit, 1, &dwRead, NULL);
            }
        }else if (strcmp(s,"pop") == 0) {
            c = '-';
        }else if (strcmp(s,"first") == 0) {
            c = 'f';
        }else if (strcmp(s,"print") == 0) {
            c = 'p';
        }else if (strcmp(s,"empty") == 0) {
            c = 'e';
        }else if (strcmp(s,"help") == 0) {
            c = 'h';
        }else if (strcmp(s,"quit") == 0) {
            c = 'q';
        }else {
            c = '?';
        }
        if (!correct()) c = '?';
        WriteFile(hStdout, &c, 1, &dwRead, NULL);
        if (c == 'q') break;
        if (c == '+') WriteFile(hStdout, &val, sizeof(int), &dwRead, NULL);
    }
    return 0;
}

谢谢大家的帮助!