一. 管道分为有名管道和无名管道
1. 无名管道:
有关无名管道的函数:(管道文件的读写可以用文件IO来读写)
int fd[2]; //int型的数组,大小为2,用来存放无名管道的文件描述符
int p = pipe[fd]; //pipe为无名管道的创建,创建无名管道的读端fd[0]和写段fd[1]的文件描述符
if(-1 == p)
{
perror(“pipe”);
return -1;
}
write(fd[1],”要写入的数据”,数据的大小); //从写端写入 数据到管道
char str[64] = {0};
read(fd[0],str,sizeof(str)); //从管道的读端读取数据
printf(“%s\n”,str);
无名管道的特点:
a、没有名字,因此无法使用open()打开
b、只能用于亲缘进程间(如父子进程、兄弟进程、祖孙进程等)通信
c、半双工工作方式,读写端是分开的,pipefd[0]为读端,pipefd[1]为写端
d、是一种特殊的文件,只存在内存中,由内核进行管理
e、对于它的读写可以使用文件IO如read、write函数
f、无名管道的操作属于一次性操作,如果对无名管道进行读操作,数据会被全部读走
例:
同一进程中两个线程的通信:
int fd[2];
int p = pipe[fd];
if(-1 == p)
{
perror(“pipe”);
return -1;
}
Pid_t pid = fork(); //创建一个子线程
4. 共享内存(shm)
1.通过ftok获取key号
ftok的第一个参数是一个文件的路径名称.一般在应用系统中,使用$HOME或者应用系统的根目录作为它的值.这样产生的key_t就不会与系统中其他的软件和系统的相同了,从而避免造成冲突. (当以文件为第一个参数时,如果文件的大小发生变化,生成的Key也会响应变化,应注意 )
key_t key = ftok(“\”,1); //获取key号
if(-1 == key)
{
Perror(“ftok”);
return -1;
}
2.创建共享内存得到共享内存的id号
int shmget(key_t key, size_t size, int shmflg);
第一个参数就是ftok的返回值key;第二个参数是创建的共享内存的大小,第三个参数共享内存的权限
int shmid = shmget(key,1024,IPC_CREAT|0666); // 通过key来创建共享内存,获取shmid号
if(shmid == -1)
{
Perror(“shmget”);
return -1;
}
3.映射共享内存,得倒共享内存的地址
void *shmat(int shmid, const void *shmaddr, int shmflg);
第一个参数是共享内存的id,第二个参数一般写NULL,代表让系统自己分配空间,第三个参数:0代表可读可写,SHM_RDONLY代表只读
char * p = shmat(shmid,NULL,0); //映射共享内存得倒共享内存的地址,失败返回NULL
If(NULL == p)
{
perror(“shmat”);
return -1;
}
4.创建进程,直接用共享内存进行传输数据
Pid_t pid = fork();
if(pid < 0)
{
perror(“fork”);
return -1;
}
else if(pid == 0)
{
while(1){
char str[32] = {0};
strcpy(shat,str); //写入数据
if(strncmp(str,”q”,1) == 0) //设置结束条件
{
break ;
}
memset(str,0,sizeof(str)); //清空数组的数据
}
}
else{
while(1){
waitpid(-1,NULL,WNOHANG); //等待子进程结束,无阻塞
printf(“shat = %s\n”,shat); //将内存中的数据打印
if(strncmp(shat,”q”,1) == 0) //设置结束条件
{
break ;
}
}
}
5.解除断开映射
int shmdt(映射后的地址):卸载/断开共享内存
当进程不需要此共享内存时,就需要去断开。该函数并不删除所指定的共享内存区,而是将之前用shmat函数连接好的共享内存区脱离目前的进程。
int ret = shmdt(shat);
If(ret == -1)
{
perror("shmdt”);
return -1;
}
6.删除共享的内容
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
第一个参数:共享内存的ID。第二个参数:设置为IPC_RMID时表示可以删除共享内存。第三个参数:设置为0即可。
int ctl = shmctl(shmid,IPC_RMID,NULL);
If(ctl == -1)
{
perror(“shmctl”);
return -1;
}
5.消息队列(msg)
1.获取key-----ftok()
key_t key = ftok(“\”,10); //获取key号
if(-1 == key)
{
Perror(“ftok”);
return -1;
}
2.创建消息队列
msgget:创建或打开一个消息队列
参数:
key: key值
msgflg: IPC_CREAT|0666
返回值:
成功:msgid值
失败:-1
IPC_CREAT:表明新创建一个消息队列。
int msgid =msgget(key,IPC_CREAT | 0666); //msgget创建消息队列,成功就返回该消息队列的id,失败返回-1;
if(-1 == msgid)
{
Perror(“msgget“);
return -1;
}
3.进程间通信--信息的发送
int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg);
功能:发送数据
参数:
msgid: msgid值
msgp: &msg (结构体变量的地址)
msgsz: 消息正文的长度 sizeof(msg) - sizeof(long)
msgflg:
IPC_NOWAIT: 非阻塞
0 : 阻塞
返回值:
成功: 0
失败:-1
pid_t pid = fork(); //创建子进程
if(pid < 0)
{
perror(“fork”);
return -1;
}
else if(pid == 0)
{
//子进程发送消息
struct msgbuf msg; //定义一个msgbuf类型的结构体变量
char str[64] = {0};
msg.mtype = 10; //信号的类型定义为10;
while(1){
gets(str); //获取字符串
strcpy(msg.mtext,str); //将数据给到msg中保存数据的数组
//消息的发送
megsnd(msgid,&msg,sizeof(msg) - sizeof(long),0);
//退出条件
if(strncmp(str,”quit”,4) == 0)
{
break;
}
memset(str,0,sizeof(str));
}
}
用到的 结构体:
struct msgbuf {
long mtype; /* message type, must be > 0 */ 消息的类型
char mtext[N]; /* message data */ 正文
};
struct msgbuf msg; //定义一个结构体变量
4.进程间的通信---信息的接收
ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:接收数据
参数比发送数据的多了一个long msgtyp:消息的类型,这个要跟发送的信息类型一致,不然接收不到
while(1){
waitpid(-1,NULL,WNOHANG);
//消息的接收
megrcv(msgid,&msg,sizeof(msg) - sizeof(long),10,0);
printf(“mtxt = %s\n”,msg.mtext);
//退出条件
if(strncmp(str,”quit”,4) == 0)
{
break;
}
memset(str,0,sizeof(str));
}
5. 删除消息队列
int msgctl(int msgid, int cmd, struct msqid_ds *buf);
功能: 控制函数
参数:
msgid: msgid值
cmd: IPC_RMID (删除消息队列)
buf: NULL
返回值:
成功; 0
失败:-1
int ctl = msgctl(msgid,IPC_RMID,NULL);
If(ctl == -1)
{
perror(“msgctl”);
return -1;
}