c - C:无法从连接到子进程标准输出的管道中读取
问题描述
我正在尝试创建一个控制台音乐播放器的前端,我必须通过向它发送命令来与它交互,stdin
同时从它的读取它的状态stdout
,所以我为此设置了 2 个管道。向子进程发送命令stdin
有效,但我无法从中读取任何数据stdout
(read()
始终返回 -1,errno
设置为Resource temporarily unavailable
)。
当在终端中使用相同的参数自行启动音乐播放器时,它会输出以下内容:
S05:05
T00:00
T00:01
T00:02
T00:03
T00:04
T00:05
...
该音乐播放器的每一行都保证是 6 行 + 换行符,因此父程序的预期输出应该是:
S05:05 T00:00 T00:01 T00:02 T00:03 T00:04 T00:05...
(当终端设置为原始模式时,换行符不起作用)
但是,根本没有从子进程中读取任何内容。关于为什么会发生这种情况以及如何解决这个问题的任何帮助将不胜感激。
这是父程序的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
system("/bin/stty raw"); // Set up the terminal so that stdin is non-blocking
pid_t p;
int pipe_stdin[2], pipe_stdout[2];
if(pipe(pipe_stdin)) return -1; // Initialize child stdin pipe
if(pipe(pipe_stdout)) return -1; // Initialize child stdout pipe
// Make reading from the pipe non-blocking
fcntl(pipe_stdout[0], F_SETFL, fcntl(pipe_stdout[0], F_GETFL) | O_NONBLOCK);
if((p = fork()) == 0) { // Create the child process
close(pipe_stdin[1]); // Close unnecessary pipe ends to the child
close(pipe_stdout[0]);
dup2(pipe_stdin[0], 0); // Redirect stdin to a pipe
dup2(pipe_stdout[1], 1); // Redirect stdout to a pipe
// Start the process
execl("/bin/sh", "sh", "-c", "./openmpt ./spacedeb.mod 2>/dev/null", NULL);
exit(1);
}
close(pipe_stdin[0]); // Close unnecessary pipe ends to the parent
close(pipe_stdout[1]);
int codec_write = pipe_stdin[1], codec_read = pipe_stdout[0], playing = 1;
char buf[8];
while(playing) {
// Read input from the child process (read() always returns -1 here!)
while(read(codec_read, buf, 7) >= 0) {
printf("%s ", buf);
}
// Send user data to the child process (this part works!)
switch(getchar()) {
case ' ': write(codec_write, "P\n", 2); break; // Play & Pause
case 13: write(codec_write, "R\n", 2); break; // Reset
case 27: playing = 0; break; // Exit
}
}
close(codec_write); // Close the pipes
close(codec_read);
system("killall -9 openmpt"); // Kill the child process
system("/bin/stty cooked"); // Reset the terminal back to its original state
}
这是播放器的代码(如有必要,这应该不是问题):
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <libopenmpt/libopenmpt.h>
#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
#include "portaudio.h"
#define BUFFERSIZE 512
#define SAMPLERATE 48000
static int16_t buffer[BUFFERSIZE * 2];
int main(int argc, char *argv[]) {
// Initialize OpenMPT and load the module
FILE *file = fopen(argv[1], "rb");
openmpt_module *mod = openmpt_module_create2(openmpt_stream_get_file_callbacks(), file, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
fclose(file);
// Output the length of the tune
printf("T%02d:%02d\n", (int)openmpt_module_get_duration_seconds(mod) / 60, (int)openmpt_module_get_duration_seconds(mod) % 60);
// Initialize PortAudio
PaStream *stream;
Pa_Initialize();
Pa_OpenDefaultStream(&stream, 0, 2, paInt16, SAMPLERATE, BUFFERSIZE, NULL, NULL);
Pa_StartStream(stream);
unsigned long i, count = 0, prev = -1, paused = 0;
char buf[3] = { 0 };
// Set stdin to non-blocking
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
while (1) {
// Read commands from the parent program
while(read(0, buf, 2) >= 0) {
switch(buf[0]) {
case 'P':
paused ^= 1;
printf("%s--:--\n", paused ? "P" : "R");
break;
case 'R':
openmpt_module_set_position_order_row(mod, 0, 0);
break;
}
}
// Display the current position of the tune
if((int)openmpt_module_get_position_seconds(mod) != prev) {
printf("T%02d:%02d\n", (int)openmpt_module_get_position_seconds(mod) / 60, (int)openmpt_module_get_position_seconds(mod) % 60);
prev = (int)openmpt_module_get_position_seconds(mod);
}
// Play audio, if not paused
if(!paused) {
count = openmpt_module_read_interleaved_stereo(mod, SAMPLERATE, BUFFERSIZE, buffer);
if (!count) {
break;
}
Pa_WriteStream(stream, buffer, count);
}
}
// Tell the parent that we're done
printf("E--:--\n");
// Stop PortAudio
Pa_StopStream(stream);
Pa_CloseStream(stream);
Pa_Terminate();
// Stop OpenMPT
openmpt_module_destroy(mod);
}
解决方案
没关系,我自己想通了,玩家需要fflush(stdout);
在printf
声明之后。现在一切都按预期工作。
推荐阅读
- assembly - 汇编语言。NASM 计算器
- url - 打开 URL FileMaker 服务器脚本
- c# - 图表系列一阶导数
- html - 控制网格项目图像的高度
- python - 如何在 Jupyter 选项卡小部件中显示 matplotlib 图?
- angular - 在“AuthenticationInterceptor”类型中具有可观察“拦截”的 HttpInterceptor 不是 > 基类型“HttpInterceptor”中的相同属性
- javascript - 在 JS 中获取更新的 PHP 数据
- vba - VBA根据选择和预定列在过滤列表中选择可见范围
- python - Django 查看测试:无法从客户的帖子中提取上下文
- clang++ - Clang 格式输出错误