师承——陈立臣
文章目录
进程间通信分类
管道(无名管道、命名管道)
,消息队列
,信号量
,共享内存
,socket套接字
,streams
一、管道
1.无名管道
特点:
1.无名管道只适用于亲缘进程
(父子进程,兄弟进程);
2.无名管道拥有固定的读端,写端,是半双工的
。数据只能单向流动;
3.无名管道是一种特殊的文件,不属于文件系统
,只存在于内存中。(建议搜索Linux中的七大文件类型
)
创建无名管道
父进程读,子进程写:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
int ret;
pid_t pid;
int pipefd[2];
char* buf;
buf=(char*)malloc(sizeof(buf)+8);
ret=pipe(pipefd);
if(ret<0){
printf("create pipe failed!\n");
return -1;
}
pid=fork();
if(pid>0){
printf("this is father!\n");
close(pipefd[1]);
read(pipefd[0],buf,sizeof(buf)+8);
printf("i get mes:%s\n",buf);
wait(NULL);
}
else if(pid==0){
printf("this is child!\n");
close(pipefd[0]);
write(pipefd[1],"hello pipe",strlen("hello pipe"));
exit(0);
}
return 0;
}
2.命名管道(FIFO)
特点:
1.全双工,可以在无关的进程之间交换数据
2.存在于文件系统当中
命名管道编程实战
read.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<stdlib.h>
int main()
{
int ret;
int fd;
char* buf;
buf=(char*)malloc(sizeof(buf)*10);
ret=mkfifo("./fifo",0600);//创建命名管道,会在当前文件夹生成相应的文件名
if(ret<0){
printf("create fifo failed!\n");
perror("why");
}
fd=open("./fifo",O_RDONLY);//打开命名管道文件
if(fd<0){
printf("open failed!\n");
}
read(fd,buf,sizeof(buf)*10);//读出命名管道中的数据,若没有则阻塞
printf("get data from write:%s\n",buf);
close(fd);
return 0;
}
write.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<string.h>
#include <unistd.h>
int main()
{
int fd;
fd=open("./fifo",O_WRONLY);//打开命名管道文件
if(fd<0){
printf("open failed!\n");
}
write(fd,"this is from write",strlen("this is from write"));//向命名管道文件中写入数据
close(fd);
return 0;
}
二、消息队列
消息对列实际上是一个消息链表,存在于内核当中,一个消息队列由一个标识符(队列ID)标识。
特点:
1.消息队列是面向记录的(消息队列是由链表组成,每一个链表节点就是一个结构体),其中的消息有特定的格式
以及特定的优先级
。
2.消息队列由内核掌控,读写进程终止,消息队列中的内容不会删除
。
3.随机查询
,不一定按照先进先出的顺序读写,也可以按照消息类型读写。
1.创建消息队列
思路:
1.创建消息队列;
2.B进程如何加消息(数据)到队列;
3.A进程如何从队列获取消息(数据);
msgsend.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
int msgId;
key_t key;
struct msgbuf sendbuf={
.mtype=888,
.mtext="this is from send"
};
struct msgbuf readbuf;
key=ftok(".",1);//获取键值,也就是id号
printf("the key is %x\n",key);
msgId=msgget(key,IPC_CREAT|0777);
if(msgId<0){
printf("create msg queue failed1\n");
perror("failed");
}
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgsnd(msgId,&sendbuf,sizeof(sendbuf.mtext),0);
printf("send over!\n");
msgrcv(msgId,&readbuf,sizeof(readbuf.mtext),988,0);
printf("get msg from 988 queue:%s\n",readbuf.mtext);
return 0;
}
msgread.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main()
{
int msgId;
key_t key;
struct msgbuf readbuf;
struct msgbuf sendbuf={
.mtype=988,
.mtext="read finsh now it's send for read pro"
};
key=ftok(".",1);//获取key键值,在消息队列,信号量,共享内存都要使用
printf("the key is %x\n",key);
msgId=msgget(key,IPC_CREAT|0777);//创建消息队列返回消息队列的ID号
if(msgId<0){
printf("create msg queue failed1\n");
perror("failed");
}
//ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
msgrcv(msgId,&readbuf,sizeof(readbuf.mtext),888,0);//从消息队列中读取数据
printf("get msg from 888 queue:%s\n",readbuf.mtext);
printf("read over!\n");
msgsnd(msgId,&sendbuf,sizeof(sendbuf.mtext),0);//向消息队列发送数据
msgctl(msgId,IPC_RMID,NULL);//从消息队列中移除
return 0;
}
三、共享内存
特点:
共享内存是IPC方式中最快
的用的也是最多的,但是也有一定的局限性:若多个进程在同时进行写操作时,共享内存中的数据会出现问题
,经常会和信号量一起配合使用。
1.共享内存的创建
思路:
1.创建共享内存
2.映射到独自的进程空间
3.数据交换
4.释放共享内存
从共享内存读数据:
#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include<unistd.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
int shmid;
key_t key;//获取键值
char* p;
key=ftok(".",1);
shmid=shmget(key,1024*4,IPC_CREAT|0666);//创建共享内存,第二个参数必须是一兆的倍数
if(shmid<0){
printf("create mem failed!\n");
return -1;
}
//void *shmat(int shmid, const void *shmaddr, int shmflg);
p=shmat(shmid,0,0);//将共享内存映射到进程中
printf("shmat ok!\n");
sleep(5);//睡五秒等待数据读取
printf("the data from mem is %s\n",p);
shmdt(p);//释放共享内存
return 0;
}
向共享内存写数据:
#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
int shmid;
key_t key;
char* p;
key=ftok(".",1);
shmid=shmget(key,1024*4,0);
if(shmid<0){
printf("create mem failed!\n");
return -1;
}
//void *shmat(int shmid, const void *shmaddr, int shmflg);
p=shmat(shmid,0,0);
printf("shmat ok!\n");
strcpy(p,"you are handsome!");//向共享内存的地址写入数据
shmdt(p);
shmctl(shmid,IPC_RMID,NULL);//删除共享内存
return 0;
}
2.查看共享内存
ipcs -m
3.删除共享内存
ipcrm -m 共享内存的ID号
四、信号
五、信号量
可以翻阅我之前的博文
信号量
六、套接字(socket)
用于不同的物理机之间通过网络的多机通信
套接字网络编程我打算单独列出来写,后续也将更新在我的主页,请大家点点关注,多多支持!谢谢!