我正在開發一個程式,其中主程式自行分叉,子行程呼叫 exec。我已經設定它,以便父行程有 2 個管道StdOutPipe和StdInPipe,子行程呼叫 dup 以便stdout寫入StdOutPipe和stdin讀取StdInPipe。然后父行程呼叫等待,之后我想將整個 StdOutPipe 讀入緩沖區。我知道你可以通過一次讀取一個字符來做到這一點,但是有沒有更快的方法呢?
uj5u.com熱心網友回復:
出于性能原因,通常一次讀取一個塊,而不是一次讀取一個字符。
- 環形,
- 嘗試擴大緩沖區,以便它可以容納更多的 CHUNK_SIZE 位元組。
- 如果發生錯誤,
- 失敗。
- 嘗試將 CHUNK_SIZE 位元組從管道讀取到緩沖區的未使用部分。
- 如果發生錯誤,
- 失敗。
- 如果達到 EOF,
- 休息。
- 讀取的位元組數增加了讀取的總位元組數。
uj5u.com熱心網友回復:
管道基本上是一個位元組流,這意味著:
- 管道沒有訊息或訊息邊界的概念
- 從管道讀取的行程可以讀取任意大小的資料塊,而與寫入行程寫入的塊大小無關
從管道讀取通常會被阻塞,直到至少一個位元組被寫入管道。
也就是說,這就是我將如何實施您的問題。
- 創建兩個管道,stdinpipe 和 stdoutpipe
- 做一個叉子
- 父行程應該關閉管道的寫入端并處于回圈中,等待資料寫入管道
- 子行程應關閉管道的讀取端并將 STDOUT 復制到 stdoutpipe 并將 STDIN 復制到 stdinpipe
- 然后子行程可以執行 exec。
示例代碼:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define STDPIPE_BUFFER_SIZE 4096
#define ARGV_SIZE 3
int main()
{
// Stdoutpipe and stdint pipe
int stdoutpipe[2], stdinpipe[2], stdin_char_count, stdout_char_count, stdout_read, stdin_read;
pid_t pid;
char stdinbuffer[STDPIPE_BUFFER_SIZE], stdoutbuffer[STDPIPE_BUFFER_SIZE];
char *argv[ARGV_SIZE]; // arguments to exec
if (pipe(stdinpipe) == -1 || pipe(stdoutpipe) == -1)
exit(1); // error occurred
// Fork and exec
switch (pid = fork())
{
case -1:
exit(1); // error
case 0:
// child close the read end of both pipes
if (close(stdinpipe[0]) == -1 || close(stdoutpipe[0]) == -1)
exit(1);
// have the pipes as the new STDIN and STDOUT
if (dup2(stdinpipe[1], STDIN_FILENO) == -1 || dup2(stdoutpipe[1], STDOUT_FILENO) == -1)
exit(1);
argv[0] = "/usr/bin/ssh"; // replace with your own program [ssh -V in my case]
argv[1] = "-V";
argv[2] = NULL;
execve(argv[0], argv, NULL);
exit(1); // if we get here something horribly bad happened
default:
// parent process
stdin_char_count = 0;
stdout_char_count = 0;
// parent close write end of both pipes
if (close(stdinpipe[1]) == -1 || close(stdoutpipe[1]) == -1)
exit(1);
for (;;)
{
stdin_read = read(stdinpipe[0], stdinbuffer, STDPIPE_BUFFER_SIZE);
stdout_read = read(stdinpipe[0], stdinbuffer, STDPIPE_BUFFER_SIZE);
if (stdin_read == 0 && stdout_read == 0)
{
stdinbuffer[stdin_char_count] = '\0';
stdoutbuffer[stdout_char_count] = '\0';
break;
}
if (stdin_read == -1 && stdout_read == -1)
exit(1); // we cant recover from this
stdin_char_count = stdin_read;
stdout_char_count = stdout_read;
}
printf("%s\n", stdoutbuffer);
wait(NULL);
}
}
來源:https ://man7.org/linux/man-pages/man2/pipe.2.html
uj5u.com熱心網友回復:
您可以將管道轉換為普通流,然后使用您認為方便的任何函式來讀取資料。在這里,getdelim()可用于讀取所有不需要通過管道發送的 NUL 位元組的文本。為簡潔起見,部分省略了錯誤檢查。
另請注意,如果您想在打開流后繼續直接與管道互動,您可能需要禁用流上的緩沖。
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
int fds[2];
if(pipe(fds) == -1) {
perror("Failed to create pipe");
exit(EXIT_FAILURE);
}
const pid_t pid = fork();
if(pid == -1) {
perror("Failed to fork");
exit(EXIT_FAILURE);
}
if(!pid) {
close(fds[0]);
const char *const msg = "Hello, world!";
if(write(fds[1], msg, strlen(msg)) == -1) {
perror("Failed to write");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
close(fds[1]);
FILE *const stream = fdopen(fds[0], "r");
if(!stream) {
perror("Failed to create stream");
exit(EXIT_FAILURE);
}
char *text = NULL;
assert(wait(NULL) != -1);
getdelim(&text, &(size_t){0}, '\0', stream);
fclose(stream);
assert(text);
puts(text);
free(text);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/449994.html
