簡體   English   中英

C Unix管道示例

[英]C Unix Pipes Example

試圖實現一個shell,主要是管道。 我已經編寫了這個測試用例,我希望將其簡單地傳遞給wc ......它肯定不能按預期工作。 它將ls打印到終端然后打印耗盡的內存。 我很失落如何解決這個問題並讓它發揮作用。 find_path適用於我的所有測試。

編輯 - 我必須使用execv為項目,它是一個類的東西,但我已經嘗試使用execvp以防萬一,它完全相同的事情。 這也只是一個例子,一個測試,看看為什么它不起作用,我為fork和waitpid調用fork兩次,因為我沒有別的事可做。

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
int find_path(char* execname, char** dst)
{        
        char *path = getenv("PATH");
        path = strdup(path);
        char *pos;
        path = strtok_r(path, ":", &pos);
        char *originalpath  = path;
        do
        {
                char* test = (char*)calloc(strlen(path) + strlen(execname) + 2, sizeof(char));
                test = strcpy(test, path);
                int testlen = strlen(test);
                (*(test+testlen)) = '/';
                strcpy(test + testlen + 1,execname);
                struct stat buf;
                int result = stat(test, &buf);
                if (result == 0)
                {
                        *dst = test;
                        free (originalpath);
                        return 1;
                }
                else
                {
                        free(test);
                }

        } while ((path = strtok_r(NULL, ":", &pos)) != NULL);
        free(originalpath);
        return 0;
}

int main()
{
    char *cmd1 = "ls";
    char *cmd2 = "wc";
    int filedes[2];
    pipe(filedes);
    char** argv = (char**)calloc(1, sizeof(char*)); 
    argv[0] = (char*)malloc(sizeof(char*));
    argv[0] = NULL;

    pid_t pid = fork();
    if (pid == 0)
    {
        char *path;
                find_path(cmd1, &path);
        dup2(filedes[1],stdout);

        execv(path,argv); 
    }
    pid = fork();
    if (pid == 0)
    {
        dup2(filedes[0], stdin);
        char *path;
        find_path(cmd2, &path);
        execv(path, argv);

    }
    else
        waitpid(pid);

}

通常,當調試程序很困難時,最好將其簡化一點以消除錯誤來源。 這是你的程序,簡化為刪除find_path作為錯誤來源:

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

int main(void)
{
    int filedes[2];
    pipe(filedes);

    /* Run LS. */
    pid_t pid = fork();
    if (pid == 0) {
        /* Set stdout to the input side of the pipe, and run 'ls'. */
        dup2(filedes[1], 1);
        char *argv[] = {"ls", NULL};
        execv("/bin/ls", argv);
    } else {
        /* Close the input side of the pipe, to prevent it staying open. */
        close(filedes[1]);
    }

    /* Run WC. */
    pid = fork();
    if (pid == 0) {
        dup2(filedes[0], 0);
        char *argv[] = {"wc", NULL};
        execv("/usr/bin/wc", argv);
    }

    /* Wait for WC to finish. */
    waitpid(pid);
}

這應該像你期望的那樣。

在簡化過程中,出現了一些錯誤:

  • argv[]沒有正確設置,特別是argv [0]被設置為NULL;
  • 程序沒有關閉給ls的管道輸入端。 ls完成時,管道沒有被關閉(因為wc過程仍然打開它),防止wc完成。
  • 該程序混淆了值stdoutstdin (類型為FILE* )與文件描述符號01 (由duppipe等使用)

您可以做很多事情來改進這些代碼(例如將其分解為較小的函數將是一個開始),但我懷疑您的內存不足問題來自find_path()中的代碼,您可以完全避免使用execvp將使用標准PATH機制為您找到可執行文件。 使用sigaction安裝信號處理程序來處理SIGCHLD並從信號處理程序調用waitpid可能是一個好主意,而不是像你正在那樣只調用waitpid()ad-hoc。 您似乎要求的次數比您想要的多,並且您沒有檢查錯誤。 希望這些建議有所幫助

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM