C->;Shell—在读之前写入的块

C->;Shell—在读之前写入的块,c,shell,C,Shell,我想把一个字符从c程序发送到shell程序。我使用命名管道发送字母“a”,无论何时需要。我只需要打开管道一次。下面是一个例子: #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> int main(){ int fd; mkfifo("/tmp/test", 0666); fd = open("/tmp/test

我想把一个字符从c程序发送到shell程序。我使用命名管道发送字母“a”,无论何时需要。我只需要打开管道一次。下面是一个例子:

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
int main(){
    int fd;
    mkfifo("/tmp/test", 0666);
    fd = open("/tmp/test", O_WRONLY);
    printf("Opened\n");
    char * a = "a";
    while(1){
            printf("Writing to pipe...\n");
            write(fd,a,1);
            sleep(1);
    }
}
问题是在一个头部之后,即使没有人,c也会源源不断地流入管道

我注意到open()会一直阻塞,直到有人在另一端。如何让write()在有人阅读之前阻止

我宁愿在write()上使用此功能,也不愿在read()上使用此功能,因为我认为在为每个请求打开文件时会有很多开销

谢谢

更新 这就是我在Java中处理它的方式,它会等到有人监听这个管道后再继续。也许只是因为它是一种更高级的语言

public static void writeToPipe(int val, String pipename){
    try{
        pipe_out = new PrintStream("/tmp/" + pipename);
    }catch(Exception e){
        System.out.println("Could not open a pipe for output!");
        e.printStackTrace();
    }
    try{
        pipe_out.println(val);
    }catch(Exception e){
        System.out.println("Could not write to pipe!");
        e.printStackTrace();
    }

    try{
        pipe_out.close();
    }catch(Exception e){
        System.out.println("Could not close the output pipe!");
        e.printStackTrace();
    }
}
更新#2-这是解决方案 这是我基于David的想法编写的代码,虽然很粗糙,但很有效。我不是检查命名管道是否存在,只是禁止它退出

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char **argv){
    mkfifo("/tmp/test", 0666);
    while(1){
      int fd, status;
            if ((fd = open ("/tmp/test", O_WRONLY)) == -1) {
         perror ("open failed");
         return 1;
            }
     printf("Opened Pipe\n");
     char a = 'a';
            int f  = fork();
            if(f == -1){
                    perror("fork");
                    exit(1);
            }else if(f == 0){
                    //This is by the child process
                    if (write (fd, &a, 1) == -1) {
                            close(fd);
                    perror ("open failed");
                            return 1;
         }

            }else{
                    //This is the parent process
                    int w = waitpid(f, &status, WUNTRACED | WCONTINUED);
                    if (w == -1){
                            perror("waitpid");
                            exit(EXIT_FAILURE);
                    }
            }
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv){
mkfifo(“/tmp/test”,0666);
而(1){
int fd,状态;
如果((fd=open(“/tmp/test”,仅限O_WRONLY))=-1){
perror(“开放式失败”);
返回1;
}
printf(“打开的管道”);
字符a='a';
int f=fork();
如果(f==-1){
佩罗尔(“福克”);
出口(1);
}else如果(f==0){
//这是通过子进程实现的
if(写入(fd,&a,1)=-1){
关闭(fd);
perror(“开放式失败”);
返回1;
}
}否则{
//这是父进程
int w=等待PID(f,&status,WUNTRACED | WCONTINUED);
如果(w==-1){
佩罗(“waitpid”);
退出(退出失败);
}
}
}
}

因为您不必检查
write
的返回,所以您甚至没有注意到它失败了。(也就是说,它不是无休止地流入管道;它只是对你撒谎,并打印“向管道写入…”,而没有向管道写入。)

阻止写入的唯一方法是填充管道。但那不是你的问题。问题是管道已经终止。如果您想保持该管道打开,则需要一些进程仍处于活动状态,从中读取数据。例如,您可以在其他shell中执行
sleep500
。或者只需打开fifo在程序中进行写入读取。(例如,添加行
open(“/tmp/fifo”,仅限ordu);


更奇怪的问题是;为什么您的程序没有从SIGPIPE终止?

既然您不必检查
write的返回,您甚至没有注意到它失败了。(也就是说,它不是无休止地流入管道;它只是对你撒谎,并打印“向管道写入…”,而没有向管道写入。)

阻止写入的唯一方法是填充管道。但那不是你的问题。问题是管道已经终止。如果您想保持该管道打开,则需要一些进程仍处于活动状态,从中读取数据。例如,您可以在其他shell中执行
sleep500
。或者只需打开fifo在程序中进行写入读取。(例如,添加行
open(“/tmp/fifo”,仅限ordu);


更奇怪的问题是;为什么程序没有从SIGPIPE终止?

您可以尝试执行您正在尝试的操作,但是您必须了解,您必须在shell端将读取限制为一个字符,因为不会有
'\n'
写入管道。此外,您可以
写入
的次数比shell
读取
的次数多得多。例如,您可以按照Pursell先生的建议添加验证,以确保您的C程序正常运行,并在
write
上使用类似以下内容进行阻塞:

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main (int argc, char **argv) {

    int fd;
    errno = 0;

    if (mkfifo (argc > 1 ? argv[1] : "/tmp/test", 0666)) {
        perror ("mkfifo failed");
        return 1;
    }
    if ((fd = open ("/tmp/test", O_WRONLY)) == -1) {
        perror ("open failed");
        return 1;    
    }

    printf ("Opened\n");
    char a = 'a';

    while (1) {
        printf ("Writing to pipe...\n");
        if (write (fd, &a, 1) == -1) {
            perror ("open failed");
            return 1;
        }
    }

    return 0;
}
您将
写入
,直到fifo缓冲区已满,导致写入管道的
比您读取的
多。


带有
叉的粗略示例

下面是一个使用
fork
生成子进程的粗略示例,以确保您的C程序在编写shell时始终处于阻塞状态。本例仅限于3次重复,但您可以使用
while(1)
连续循环。我还添加了一个快速计数器,用于
写入
(只是出于好奇)

示例Shell读取/输出

read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
$ ./bin/pipe_write_shell_fork
Opened
  0 - Writing to pipe...
  1 - Writing to pipe...
  2 - Writing to pipe...
  3 - Writing to pipe...
  4 - Writing to pipe...
    ...
138 - Writing to pipe...
139 - Writing to pipe...
140 - Writing to pipe...
shell read complete. restarting
Opened
  0 - Writing to pipe...
  1 - Writing to pipe...
  2 - Writing to pipe...
  3 - Writing to pipe...
  4 - Writing to pipe...
    ...
    130 - Writing to pipe...
131 - Writing to pipe...
shell read complete. restarting
Opened
  0 - Writing to pipe...
  1 - Writing to pipe...
  2 - Writing to pipe...
  3 - Writing to pipe...
  4 - Writing to pipe...
    ...
144 - Writing to pipe...
145 - Writing to pipe...
shell read complete. done
$ declare -i c=0; while test "$c" -lt 10 && read -n 8 ch; do \
echo "read: $ch"; ((c++)); done </tmp/test
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
$declare-ic=0;测试“$c”-lt 10和读取-n 8通道;做\

echo“read:$ch”;(c++);完成您可以尝试执行您正在尝试的操作,但是您必须了解,您必须将shell端的读取限制为一个字符,因为不会有
'\n'
写入管道。此外,您可以
写入
的次数比shell
读取
的次数多得多。例如,您可以按照Pursell先生的建议添加验证,以确保您的C程序正常运行,并在
write
上使用类似以下内容进行阻塞:

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main (int argc, char **argv) {

    int fd;
    errno = 0;

    if (mkfifo (argc > 1 ? argv[1] : "/tmp/test", 0666)) {
        perror ("mkfifo failed");
        return 1;
    }
    if ((fd = open ("/tmp/test", O_WRONLY)) == -1) {
        perror ("open failed");
        return 1;    
    }

    printf ("Opened\n");
    char a = 'a';

    while (1) {
        printf ("Writing to pipe...\n");
        if (write (fd, &a, 1) == -1) {
            perror ("open failed");
            return 1;
        }
    }

    return 0;
}
您将
写入
,直到fifo缓冲区已满,导致写入管道的
比您读取的
多。


带有
叉的粗略示例

下面是一个使用
fork
生成子进程的粗略示例,以确保您的C程序在编写shell时始终处于阻塞状态。本例仅限于3次重复,但您可以使用
while(1)
连续循环。我还添加了一个快速计数器,用于
写入
(只是出于好奇)

示例Shell读取/输出

read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
$ ./bin/pipe_write_shell_fork
Opened
  0 - Writing to pipe...
  1 - Writing to pipe...
  2 - Writing to pipe...
  3 - Writing to pipe...
  4 - Writing to pipe...
    ...
138 - Writing to pipe...
139 - Writing to pipe...
140 - Writing to pipe...
shell read complete. restarting
Opened
  0 - Writing to pipe...
  1 - Writing to pipe...
  2 - Writing to pipe...
  3 - Writing to pipe...
  4 - Writing to pipe...
    ...
    130 - Writing to pipe...
131 - Writing to pipe...
shell read complete. restarting
Opened
  0 - Writing to pipe...
  1 - Writing to pipe...
  2 - Writing to pipe...
  3 - Writing to pipe...
  4 - Writing to pipe...
    ...
144 - Writing to pipe...
145 - Writing to pipe...
shell read complete. done
$ declare -i c=0; while test "$c" -lt 10 && read -n 8 ch; do \
echo "read: $ch"; ((c++)); done </tmp/test
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
$declare-ic=0;测试“$c”-lt 10和读取-n 8通道;做\
echo“read:$ch”;((c)+