gpt4 book ai didi

C -> Shell - 阻止写入直到读取

转载 作者:行者123 更新时间:2023-11-30 16:43:48 26 4
gpt4 key购买 nike

我想将一个字符从 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);
}
}

shell 会根据需要多次执行该命令...

head -c 1 /tmp/test

问题是在一个头之后,即使没有人在那里,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);
}
}
}
}

最佳答案

您可以执行您正在尝试的操作,但请理解您必须将 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;
}

您可以使用简单的方法进行测试:

$ declare -i c=0; while test "$c" -lt 10 && read -n 1 ch; do 
echo "read: $ch"
((c++))
done </tmp/test

Shell 输出示例

read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a

您将写入直到fifo缓冲区已满,导致写入管道...比您已读取:a更多。

<小时/>

使用fork的粗略示例

继续这里的注释是一个使用 fork 生成子进程的粗略示例,以确保您的 C 程序在 shell 写入时始终阻塞。此示例仅限 3 次重复,但您可以仅使用 while (1) 进行连续循环。我还为 write 添加了一个快速计数器(只是出于我的好奇心),例如

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

int crt_fifo_write (char *fname);
int file_exists (char *f);

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

int n = 0;
errno = 0;

while (n < 3) { /* limit example to 3 child processes */

pid_t cpid, w;
int status;

cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}

if (cpid == 0) { /* Code executed by child */
if (!crt_fifo_write (argc > 1 ? argv[1] : "/tmp/test"))
fprintf (stderr, "crt_fifo_write() failed.\n");
}
else { /* Code executed by parent */
do {
w = waitpid (cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFSIGNALED(status)) /* signal on close of read end */
printf("shell read complete. %s\n",
n < 2 ? "restarting" : "done");
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
n++;
}

return 0;
}

/** your write 'a' to the fifo with check for existence & unlink */
int crt_fifo_write (char *fname)
{
int fd, n = 0;
errno = 0;

if (!fname || !*fname) return 0;

if (file_exists (fname))
if (unlink (fname) == -1) {
perror ("fifo exists unlink failed");
return 0;
}

if (mkfifo (fname, 0666)) {
perror ("mkfifo failed");
return 1;
}
if ((fd = open (fname, O_WRONLY)) == -1) {
perror ("open failed");
return 1;
}

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

while (write (fd, &a, 1) != -1) {
printf ("%3d - Writing to pipe...\n", n++);
}

return 0;
}

/** atomic test that file exists (1 success, 0 otherwise) */
int file_exists (char *f)
{
errno = 0;
int flags = O_CREAT | O_WRONLY | O_EXCL;
int mode = S_IRUSR | S_IWUSR;
int fd = open (f, flags, mode);

if (fd < 0 && errno == EEXIST)
return 1;
else if (fd) { /* created, like bash touch */
close (fd);
unlink (f);
}

return 0;
}

示例程序使用/输出

$ ./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

Shell 读取/输出示例

$ 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

(再重复 2 次)

关于C -> Shell - 阻止写入直到读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44974699/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com