进程间通信:
有名管道:
FIFO,也称为命名管道,它是一种文件类型。
1、特点
-
FIFO可以在无关的进程之间交换数据,与无名管道不同。
-
FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
-
一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO
代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char buf[64] = {0}; //读数据程序
int fd = mkfifo("fifo.tmp", S_IRWXU); //建立有名管道
if(fd == -1)
{
perror("mkfifo");
exit(1);
}
int ret;
ret = open("fifo.tmp", O_RDONLY );//以只读方式打开管道
if(ret == -1)
{
perror("open");
exit(1);
}
while(1)
{
int ret1;
ret1 = read(ret, buf, sizeof(buf));
if(ret1 == -1)
{
perror("read");
exit(1);
}
if(!strcmp(buf, "bye"))
{
break;
}
printf("%s\n",buf);
memset(buf, 0, sizeof(buf));
}
unlink("fifo.tmp");
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char buf[64] = {0};
int ret;
ret = open("fifo.tmp", O_WRONLY);//以只写方式打开有名管道
if(ret == -1)
{
perror("open");
exit(1);
}
while(1)
{
int ret1;
scanf("%s",buf);
ret1 = write(ret, buf, strlen(buf));//将数据写入管道
if(ret1 == -1)
{
perror("write");
exit(1);
}
if(!strcmp(buf, "bye"))
{
break;
}
memset(buf, 0, sizeof(buf));
}
return 0;
}
消息队列实现进程间通信:
消息队列就是一个消息的链表.可以把消息看作一个记录,具有特定的格式.进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,必须提供该消息队列的键值。简单说,消息队列本身有自己的编号,不同的消息队列有不同的编号。通信双方发送的消息也有不同的消息类型。
代码:
由于实现了收发双方能够互相通信,因而加入了父子进程,
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#define MSGKEY 1234 //这是消息队列的编号,以便多个信号队列之间的通信不会交叉错乱
struct msgbuf //消息队列需要定义一个结构体
{ //第一个参数mtype就是消息的类型
long mtype; /* message type, must be > 0 */
char mtext[64]; /* message data */
};
int main()
{
struct msgbuf mbuf;
pid_t pid;
int ret;
int ret1;
int msgid = msgget(MSGKEY,IPC_CREAT | IPC_EXCL); //建立消息队列
if(msgid == -1)
{
perror("msgget");
exit(1);
}
pid = fork(); //创建父子进程
if(pid == -1)
{
perror("fork");
exit(1);
}
else if(pid == 0) //子进程用来写
{
while(1)
{
memset(&mbuf, 0, sizeof(mbuf));
mbuf.mtype = 1; //定义发送的消息类型为1
scanf("%s",mbuf.mtext);
ret = msgsnd(msgid,&mbuf,sizeof(mbuf.mtext), 0); //发送消息
if(ret == -1)
{
perror("msgsnd");
exit(1);
}
if(!strcmp(mbuf.mtext,"bye"))
{
mbuf.mtype = 2; //如果发送了"bye",需要结束全部进程,就需要给接收消息类型
msgsnd(msgid,&mbuf,sizeof(mbuf.mtext), 0);//为2的父进程发送"bye",让父进
break; //程结束
}
}
}
else
{
while(1)
{
ret1 = msgrcv(msgid,&mbuf,sizeof(mbuf.mtext), 2, 0);//父进程开始接收消息类型
if(ret1 == -1) //为2 的信息,直到接收到"bye"
{
perror("msgsnd");
exit(1);
}
if(!strcmp(mbuf.mtext,"bye"))
{
kill(pid, 2);
break;
}
printf("%s\n",mbuf.mtext);
}
}
sleep(1);
msgctl(msgid,IPC_RMID, NULL);
return 0;
}
另一端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#define MSGKEY 1234
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[64]; /* message data */
};
int main()
{
struct msgbuf mbuf;
pid_t pid;
int ret1;
int msgid = msgget(MSGKEY,0); //这一端就不需要再建立一个消息队列
if(msgid == -1)
{
perror("msgget");
exit(1);
}
int ret;
pid = fork();
if(pid == -1)
{
perror("fork");
exit(1);
}
else if(pid == 0)
{
while(1)
{
memset(&mbuf ,0, sizeof(mbuf));
mbuf.mtype = 2;
scanf("%s",mbuf.mtext);
ret1 = msgsnd(msgid,&mbuf,sizeof(mbuf.mtext), 0);
if(ret1 == -1)
{
perror("msgsnd");
exit(1);
}
if(!strcmp(mbuf.mtext,"bye"))
{
mbuf.mtype = 1;
msgsnd(msgid,&mbuf,sizeof(mbuf.mtext), 0);
break;
}
}
}
else
{
while(1)
{
memset(&mbuf ,0, sizeof(mbuf));
ret = msgrcv(msgid,&mbuf,sizeof(mbuf.mtext), 1, 0);
if(ret == -1)
{
perror("msgsnd");
exit(1);
}
if(!strcmp(mbuf.mtext,"bye"))
{
kill(pid,2);
break;
}
printf("%s\n",mbuf.mtext);
}
}
return 0;
}