C 双向管道通信。悬挂
我试图让家长向孩子发送信息,让孩子使用2个文件描述符将信息发送回去C 双向管道通信。悬挂,c,fork,pipe,parent-child,C,Fork,Pipe,Parent Child,我试图让家长向孩子发送信息,让孩子使用2个文件描述符将信息发送回去 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define READ 0 #define WRITE 1 int main(void) { int fdWrite[2]; int fdRead[2]; int pid, i, num; FILE* output; if (pipe(fdRead
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define READ 0
#define WRITE 1
int main(void) {
int fdWrite[2];
int fdRead[2];
int pid, i, num;
FILE* output;
if (pipe(fdRead) == -1) {
perror("Can't create pipe");
exit(1);
}
if (pipe(fdWrite) == -1) {
perror("Can't create pipe");
exit(1);
}
char mystring[100] = { 0 };
char c;
pid = fork();
if (pid) {
FILE * read;
FILE * write;
close(fdRead[WRITE]);
close(fdWrite[READ]);
write = fdopen(fdWrite[WRITE], "w");
fprintf(write, "parent %s\n", "jeronimooo...");
read = fdopen(fdRead[READ], "r");
fgets(mystring, 100, read);
fprintf(stdout, "%s\n", mystring);
} else {
/* child */
dup2(fdRead[WRITE], STDOUT_FILENO);
close(fdRead[READ]);
close(fdRead[WRITE]);
dup2(fdWrite[READ], STDIN_FILENO);
close(fdWrite[READ]);
close(fdWrite[WRITE]);
fgets(mystring, 100, stdin);
fprintf(stdout, "child %s\n", mystring);
}
exit(0);
}
#包括
#包括
#包括
#定义读取0
#定义写入1
内部主(空){
int-fdWrite[2];
int-fdRead[2];
int-pid,i,num;
文件*输出;
如果(管道(fdRead)=-1){
perror(“无法创建管道”);
出口(1);
}
if(管道(fdWrite)=-1){
perror(“无法创建管道”);
出口(1);
}
char mystring[100]={0};
字符c;
pid=fork();
如果(pid){
文件*读取;
文件*写入;
关闭(fdRead[WRITE]);
关闭(fdWrite[READ]);
write=fdopen(fdWrite[write],“w”);
fprintf(写入“父%s\n”、“jeronimooo…”);
read=fdopen(fdRead[read],“r”);
fgets(mystring,100,read);
fprintf(stdout,“%s\n”,mystring);
}否则{
/*孩子*/
dup2(fdRead[WRITE],标准输出文件号);
关闭(fdRead[READ]);
关闭(fdRead[WRITE]);
dup2(fdWrite[READ],标准文件号);
关闭(fdWrite[READ]);
关闭(fdWrite[WRITE]);
fgets(mystring,100,stdin);
fprintf(stdout,“子%s\n”,mystring);
}
出口(0);
}
我想做的是:
当前是挂起的:
fgets(mystring,100,read)
C I/O流通常是缓冲的,这意味着当您执行例如fprintf
时,您打印到流中的内容实际上并没有写入文件,而是写入内存缓冲区中。当缓冲区已满时,缓冲区中的数据实际上会写入文件。该函数刷新缓冲区,即获取缓冲区中的内容并立即将其写入文件
这里的问题是,当您执行fdopen
操作时,文件流是使用完全缓冲创建的(不同于stdout的行缓冲,例如stdout
),因此实际上必须填充缓冲区才能实际写入。通过显式强制写入,管道的另一端可以读取它。以下是如何使用管道的摘录,
the following is an excerpt for how to use a pipe,
extracted from a working system
where this pipe was used to kick a hardware watchdog
In general, this example only contains the code needed to :
create pipe, fork, write pipe, read pipe.
typedef struct
{
struct timespec time;
int tracking_number;
long magic;
} WatchdogRecord;
WatchdogRecord watchdog_record;
pid_t childpid;
int watchdog_pipe[2];
// open the pipe
pipe(watchdog_pipe);
// Set both ends of pipe to nonblocking
for(pipe_end=0; pipe_end<2; pipe_end++)
{
// Get previous flags
int f = fcntl(watchdog_pipe[pipe_end], F_GETFL, 0);
// Set bit for non-blocking flag
f |= O_NONBLOCK;
// Change flags on fd
fcntl(watchdog_pipe[pipe_end], F_SETFL, f);
} // for each pipe_end
// fork the child process
if ((childpid = fork()) == -1)
{ // then fork failed
perror("fork");
exit(1);
}
// implied else, fork successful
if (childpid == 0)
{ // then child process
// child closes up 'write' side of pipe
close(watchdog_pipe[1]);
// if any pipe input then store it
while (((readret = read(watchdog_pipe[0],
readbuffer+nbytes,
sizeof(readbuffer)-nbytes)) != -1)
&&
((nbytes+=readret) >= sizeof(WatchdogRecord)))
{
wdrec = (WatchdogRecord *)readbuffer;
// check magic number to make sure record is aligned properly in pipe
if (wdrec->magic == WD_MAGIC)
{
// read a full record, so reset nbytes to 0
nbytes = 0;
wd_syncerror = 0;
// and clear magic so it will have to be
// rewritten validly by the next read
wdrec->magic = 0L;
}
else // try to resynchronize
{
log_error("WDPipe Out Of Sync!, magic=0x%p\n", wdrec->magic);
//drop one of nbytes and wait for next try to resync
nbytes = 1;
// if this happens too many times, die
if (++wd_syncerror > sizeof(WatchdogRecord))
{
log_error("WDPipe Out Of Sync Too Long!\n");
watchdog_die();
} // ? too many sync errors
// fill in temporary info for wdrec so we don't use bad data
wdrec->time = curtime;
wdrec->tracking_number = -1;
} // pipe out of sync
}
else
{ // else parent process
// parent closes 'read' side of pipe
close(watchdog_pipe[0]);
// send message through pipe,
// remember pipe has no concept of record,
// so include a 'marker' so receiver can find edge of record
watchdog_record.time = curtime;
watchdog_record.tracking_number = tracking_number;
watchdog_record.magic = WD_MAGIC;
write(watchdog_pipe[1], &watchdog_record, sizeof(WatchdogRecord));
从工作系统中提取
这根管子是用来踢硬件看门狗的
通常,此示例仅包含以下所需的代码:
创建管道、分叉、写入管道、读取管道。
类型定义结构
{
结构时间段时间;
int跟踪u数;
长魔术;
}观察记录;
看门狗记录看门狗记录;
pid_t childpid;
int看门狗_管道[2];
//打开管子
管道(看门狗管道);
//将管道两端设置为非阻塞
对于(管道末端=0;管道末端=sizeof(WatchdogRecord)))
{
wdrec=(WatchdogRecord*)读缓冲区;
//检查幻数,确保记录在管道中正确对齐
如果(wdrec->magic==WD_magic)
{
//读取完整记录,因此将N字节重置为0
n字节=0;
wd_syncerror=0;
//和清晰的魔法,所以它必须是
//通过下一次读取有效重写
wdrec->magic=0L;
}
否则//尝试重新同步
{
日志错误(“WDPipe不同步,magic=0x%p\n”,wdrec->magic);
//删除其中一个N字节并等待下一次尝试重新同步
n字节=1;
//如果这种情况发生太多次,就去死吧
如果(++wd_syncerror>sizeof(WatchdogRecord))
{
日志错误(“WDPipe不同步太长!\n”);
看门狗死了;
}//?同步错误太多
//填写wdrec的临时信息,这样我们就不会使用坏数据
wdrec->time=curtime;
wdrec->跟踪号=-1;
}//管道不同步
}
其他的
{//else父进程
//父级关闭管道的“读取”侧
关闭(看门狗_管道[0]);
//通过管道发送消息,
//记住管道没有记录的概念,
//所以包括一个“标记”,以便接收者可以找到记录的边缘
看门狗_record.time=curtime;
看门狗_记录。跟踪_编号=跟踪_编号;
watchdog_record.magic=WD_magic;
写入(看门狗_管道[1],&watchdog_记录,sizeof(看门狗记录));
挂起哪个fgets
调用?有两个。另外,我不知道fdopen
使用什么缓冲模式,您可能想检查一下,这样它就不会被完全缓冲。写完之后试试fflush
。@JoachimPileborg,谢谢!您能解释一下fflush工作的原因吗?或者setvbuf(3)
来明确更改缓冲类型。