我正在创建一个基于服务器-客户端的 C 程序。
我一直在尝试将 stdin 重定向到我创建的命名管道,并且我已经设法让客户端写入管道。在服务器端,我打开同一个管道,关闭标准输入并使用 dup(也尝试使用 dup2)将标准输入重定向到管道。
我必须使用函数 getline 读取输入。问题是它正确读取了第一个输入,但在它之后只收到空值。我会在问题中添加一个示例。
服务器:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
main () {
char* str;
size_t size=0;
int pshell_in;
unlink("/tmp/par-shell-in");
if(mkfifo("/tmp/par-shell-in", 0777) < 0){
fprintf(stderr, "Error: Could not create pipe\n");
exit(-1);
}
if((pshell_in = open("/tmp/par-shell-in", O_CREAT | O_RDONLY, S_IRUSR)) < 0){
fprintf(stderr, "Error: Failed to open file\n");
exit(-1);
}
dup2(pshell_in, 0);
close(pshell_in);
while(1) {
if (getline(&str, &size, stdin)<0) {
printf("Oh dear, something went wrong with getline()! %s\n", strerror(errno));
return -1;
}
printf("%s", str);
}
}
* 我知道它是空的,因为我用 read(而不是重定向)打印了它,它打印了 (null)。
客户:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#define VECTORSIZE 7
int main() {
char* buf;
int pshell_in;
size_t size=0;
if((pshell_in = open("/tmp/par-shell-in", O_WRONLY, S_IWUSR)) < 0){
fprintf(stderr, "Error: Failed to open file\n");
exit(-1);
}
printf("%d\n", pshell_in);
while(1) {
if (getline(&buf, &size, stdin) < 0) {
return -1;
}
write(pshell_in, buf, 256);
}
}
- 我怀疑它是正确的,因为如果我在客户端使用读取(将 O_WRONLY 替换为 O_RDWR),它会在我输入时打印字符串。
谁能帮我解决这个问题?
最佳答案
FIFO 是很有趣的东西。如果一个进程试图打开一个进行读取,它将阻塞直到有一个进程打开它进行写入。相反,如果一个进程试图打开一个文件进行写入,它将阻塞,直到有一个进程打开它进行读取。但是,多个进程可以打开它进行读取或写入。当没有更多进程打开它进行读取时,写入将失败;当没有更多进程打开写入时,读取将失败。当操作失败时,您必须关闭并重新打开 FIFO 才能继续重新处理数据。
我强烈怀疑您因这些行为而遇到问题。
此外,您的客户编写的代码是可疑的;您没有注意读取了多少数据。你有:
while(1) {
if (getline(&buf, &size, stdin) < 0) {
return -1;
}
write(pshell_in, buf, 256);
}
如果您在该行中读取的输入字符少于 256 个字符,那么您很有可能会超出由 getline()
分配的数组范围进行写入。一些甚至大部分数据显然也可能是空字节。但是,您在服务器中看到的 (null)
通常表示您正在尝试打印字符串,但向 printf()
传递了一个空指针。无论发生什么,大部分都是未定义的行为,这是坏事™,应该不惜一切代价避免。
你应该有更多的东西:
ssize_t nbytes;
while ((nbytes = getline(&buf, &size, stdin)) > 0)
{
if (write(pshell_in, buf, nbytes) != nbytes)
{
fprintf(stderr, "Short write to FIFO\n");
break;
}
}
free(buf);
请注意,这只写入与读取的数据一样多的数据,并且不假设有 256 个字节可供写入。
关于c - 使用 FIFO(名称管道)重定向标准输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34036099/