我想将一个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()而不是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();
}
}
这是我的代码基于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);
}
}
}
}
答案 0 :(得分:0)
由于您不想查看write
的回复,您甚至不会注意到它失败了。 (也就是说,它不无休止地流入管道;它只是骗你并打印&#34;写入管道......&#34;失败写入管道。)
阻止写入的唯一方法是填充管道。但这不是你的问题。问题是管道已经终止。如果你想保持那个管道打开,你需要让一些进程继续读取它。例如,您可以在其他shell中执行sleep 500 < /tmp/test
。或者只是打开fifo阅读程序中的写作。 (例如,添加行open("/tmp/fifo", O_RDONLY);
)
更奇怪的问题是;为什么你的程序没有从SIGPIPE终止?
答案 1 :(得分:0)
您可以执行您正在尝试的操作,但了解您必须将读取限制在shell端的 one-char ,因为没有'\n'
写入管道。此外,您write
可能比read
多write
次。例如,您可以添加验证,因为Pursell先生建议确保您的C程序在#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
您可以使用简单的测试:
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
示例Shell输出
write
您将Writing to pipe...
直到fifo缓冲区已满,导致read: a
比fork
更多。
fork
继续这里的评论是一个粗略的例子,使用while (1)
来生成子进程,以确保您的C程序始终阻止写入shell。此示例仅限于3次重复,但您可以使用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
示例程序使用/输出
$ 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
示例Shell读取/输出
{
"sendSmsRequest": {
"to": "5511982694404",
"msg": "funcionou"
}
}
(重复2次)