ps-axj
1.进程通信:在用户空间实现进程通信是不可能的,通过linux内核通信
2.线程间通信:可以在用户空间实现,可以通过全局变量通信。
进程间通信
管道通信;无名管道,有名管道
信号通信:信号的发送,接收和处理
IPC通信:共享内存,消息队列,信号灯
soket通信:存在于一个网络中两个进程之间的通信(两个linux内核)
无名管道4
管道文件是一个特殊的文件,是由队列来实现的。单向队列。
int pipe(int fd[2]);
创建管道,为系统调用:unistd.h
例:
#include "unistd.h"
#include "stdio.h"
#include "std;ib.h"
int main()
{
int fd[2];
int ret ;
char wretebuf[]="hello linux";
char readbuf[128]={0};
ret=pipe(fd);
if(ret<0)
{
printf("creat pipe failure\n");
return -1;
}
printf("creat success fd[0]=%d,fd[1]=%d\n",fd[0],fd[1]);
wwrite(fd[1],writebuf,sizeof(writebuf));
read(fd[0],read,128);
printf("readbuf=%s\n",readbuf);
close(fd[0]);
close(fd[1]);
return 0;
}
注意:
1.管道是创建在内存中的,进程结束,空间释放,管道就不存在了。
2.管道中的内容,读完就删除了;
3.如果管道中没有东西可以读,则会读阻塞;
#include "unistd.h"
#include "stdio.h"
#include "sys/type.h"
#include "stdlib.h"
int main()
{
pid_t pid;
int fd[2];
int ret;
int process_inter=0;
ret=pipe(fd);
if(ret<0){printf("creat pipe failure\n"); return -1;}
printf(creat pipe success\n);
pid = fork();
if(pid==0)
{
int i=0;
read(fd[0],&process_inter,1);//if pipe empty child sleep
while(process_inter=0); //if father make process_inter as 1,break.
for(i=0;i<5;i++)
{
printf("this is child process i=%d\n",i);
usleep(100);
}
if(pid>0)
{
int i=0;
for(i=0;i<5;i++)
{
printf("this is father process i=%d\n",i);
usleep(100);
}
process_inter=1;
write(fd[1],&process_inter,1);
}
return 0;
}
管道文件只有inode号,不占磁盘块空间,和套接字,字符设备文件,块设备文件一样。
int mkfifo(const char *filename,mode_t mode);
创建管道文件节点(未在内核创建管道文件,open此节点之后才创建管道),实现无亲缘关系进程间通信。
创建管道节点
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
int main()
{
int ret;
ret=mkfifo("./myfifo",0777);
if(ret<0){printf("error");return -1}
printf("success")
return 0;
}
第一个进程
2 #include "unistd.h"
3 #include "stdlib.h"
4 #include "sys/types.h"
5 #include "fcntl.h"
6 int main()
7 {
8 int fd;
9 int i;
10 int process_inter=0;
11 fd=open("./myfifo",O_WRONLY);
12 if(fd<0){printf("open failure\n");return -1;}
13 printf("open myfifo success\n");
14 for(i=0;i<5;i++)
15 {
16 printf("this is first process i=%d\n",i);
17 usleep(100);
18 }
19 process_inter=1;
20 sleep(5);
21 write(fd,&process_inter,1);
22 while(1);
23 return 0;
24 }
第二个进程
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "sys/types.h"
#include "fcntl.h"
int main()
{
int fd,i;
int process_inter=0;
fd=open("./myfifo",O_RDONLY);
if(fd<0){printf("open failure\n");return -1;}
printf("open myfifo success\n");
read(fd,&process_inter,1);
while(process_inter==0);
for(i=0;i<5;i++)
{
printf("this is second process i=%d\n",i);
usleep(100);
}
while(1);
return 0;
}
gec
运行first后无输出,再运行second 才都能输出。
kill
内核里面已经存在很多信号。
kill -l 查看
信号的发送
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "sys/types.h"
#include "signal.h"
int main(int argc,char *argv[])
{
int sig;
int pid;
if(argc<3){printf("error\m");return -1;}
sig=atoi(argv[1]); //字符转化为整型
pid=atoi(argc[2]);
printf("sig=%d,pid=%d\n",sig,pid);
kill(pid,sig);
}
int raise(int sig)
发信号给自己 =kill(getpid(),sig)
父进程杀死子进程后没有回收(wait(NULL);)的话,子进程变成Z状态,僵司进程。
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "sys/types.h"
#include "signal.h"
void myfun(int signum)
{
int i;
i=0
while(i<5)
{
printf("receive signum=%d",signum)
sleep(1);
i++;
}
return;
}
void myfun1(int signum)
{
printf("receive signum=%d\n",signum);
wait(NULL);
}
int main()
{
pid_t pid;
pif=fork();
if(pid>0)
{
int i;
i=0;
signal(10,myfun);
signal(17,myfun1);
while(1)
{
printf("parent process things,i=%d\n",i);
sleep(1);
i++;
}
}
if(pid==0)
{
sleep(10)
kill(getppid(),10);//发送给父进程信号10
sleep(10);
exit(0);//kill(getppid() ,17)
}
}
共享内存创建之后一直存在于内核中,直到被删除或系统关闭。
共享内存和管道不一样,读取后,内容仍在其共享内存中。
创建共享内存
shmget
创建后查看IPC对象 ipcs -m
删除IPC对象 ipcrm -m id
两种key的获得
1.用宏创建时key为0,类似无名管道
2.:ftok获取key,类似有名管道,实现无亲缘关系的通信
*char ftok(const char path,char key)
参数:文件路径和文件名
一个字符
返回值:正确返回一个key值,出错返回-1
*void shmat(int shmid,const void shmaddr ,int shmflg)
当内核空间和用户空间存在大量数据交互时, 共享内存映射就成了这种情况下的不二选择; 它能够最大限度的降低内核空间和用户空间之间的数据拷贝, 从而大大提高系统的性能.
将共享内存映射到用户空间的地址中
参数:ID号
映射到的地址,NULL时为系统自动完成的映射
shmflg:SHM_RDONLY共享内存只读默认是0.
返回值:成功返回映射后的地址,失败返回NULL
int shmdt(const void shmaddr);
讲进程里的地址映射删除 ,内核的还在
int shmctl(int shmid, int cmd ,struct shmid_ds buf);
删除内核中共享内存对象。
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "sys/types.h"
#include "signal.h"
#include "sys/shm.h"
void myfun(int signum)
{
return;
}
int main()
{
int shmid;
int key;
char *p;
int pid;
shmid=shmget(key,128,IPC_CREAT | 0777); //创建共享内存
if(shmid <0)
{
printf("creat share memory failure\n");
return -1;
}
printf("creat share memory success shmid=%d\n",shmid);
pid=fork();
if(pid>0)
{
signal(SIGUSR2,myfun);
p=(char *) shmat(shmid,NULL,0);//共享内存映射
if(p==NULL){printf("parent shmat function failure\n");return -3;}
while(1)
{
//write share memory
printf("parent process start share memory");
fget(p,128,stdin);
kill(pid,SIGUSR1);//通知子进程读
pause();//等待子进程读
}
}
if(pid==0)
{
signal(SIGUSR1,myfun);
p=(char *) shmat(shmid,NULL,0);//共享内存映射
if(p==NULL){printf("parent shmat function failure\n");return -3;}
while(1)
{
pause();//等待父进程写,pause()函数表示让进程或者线程进入休眠状态,直到进程或线程被杀死或者**调用信号捕捉函数**
//start read share memory
printf("share memory data:%s",p);
kill(getppid(),SIGUSR2);
}
}
//system("ipcs -m");//查看共享内存
shmdt(p);//删除映射内存
shmctl(shmid,IPC_RMID,NULL);//删除共享内存
system("ipcs -m");
return 0;
}
SIGUSR1 用户自定义信号 默认处理:进程终止
SIGUSR2 用户自定义信号 默认处理:进程终止
msqid_ds :内核维护消息队列的结构体,队列的第一个消息指针msg_first,最后一个消息指针msg_last
Data:数据
Length:数据的长度
type:消息类型
头文件:
sys/types/h sys/ipc.h sys/msg.h
int msgget(key_t,int flag)
创建消息队列
*int msgctl(int msgqid, int cmd, struct msqid_ds buf);
sever.c 父进程写type100 子进程读type200
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct msgbuf
{
long type;
char voltage[124];
char ID[4];
};
int main()
{
int msgid;
int readret;
int key;
struct msgbuf sendbuf ,recvbuf;
int pid;
key=ftok("./a.c",'a');
if(key<0)
{
printf("creat key failure\n");
return -2;
}
msgid=msgget(key,IPC_CREAT|0777);//建立消息队列
if(msgid<0)
{
printf("creat message queue failure\n");
return -1;
}
printf("creat message queue success msgid=%d\n",msgid);
system("ipcs -q");
pid=fork();//创建子进程
if(pid>0)//父进程写 type100
{
sendbuf.type=100;
//写
while(1)
{
memset(sendbuf.voltage,0,124);
printf("please input message:\n");
fgets(sendbuf.voltage,124,stdin);
msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
}
}
if(pid==0)//子进程 读type200
{
while(1){
memset(recvbuf.voltage,0,124);
msgrcv(msgid,(void *)&recvbuf,124,200,0);
printf("receive message from message queue:%s",recvbuf.voltage);
}
}
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
client.c 父进程读type200 子进程写type100
#include "sys/msg.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
struct msgbuf
{
long type;
char voltage[124];
char ID[4];
};
int main()
{
int msgid;
int readret;
int key;
struct msgbuf sendbuf ,recvbuf;
int pid;
key=ftok("./a.c",'a');
if(key<0)
{
printf("creat key failure\n");
return -2;
}
msgid=msgget(key,IPC_CREAT|0777);//建立消息队列
if(msgid<0)
{
printf("creat message queue failure\n");
return -1;
}
printf("creat message queue success msgid=%d\n",msgid);
system("ipcs -q");
pid=fork();//创建子进程
if(pid==0)//zijindxie
{
sendbuf.type=200;
//写如队列
while(1)
{
memset(sendbuf.voltage,0,124);
printf("please input message:\n");
fgets(sendbuf.voltage,124,stdin);
msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
}
}
if(pid>0)//fu进程
{
while(1){
memset(recvbuf.voltage,0,124);
msgrcv(msgid,(void *)&recvbuf,124,100,0);
printf("receive message from message queue:%s",recvbuf.voltage);
}
}
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
实现了服务端和客户端双向通信
信号灯(semaphore)它是不同进程间或一个给定进程内部不同线程间同步的机制System V的信号灯是一个或者多个信号灯的一个集合(允许对集合中的多个计数信号灯进行同时操作)。其中的每一个都是单独的计数信号灯。而Posix信号灯指的是单个计数信号灯。
创建后用 ipcs -s 查看
int semop(int semid,struct senbuf opsptr,size nops);
semid:信号灯集ID
struct sembuf
{
short sen num;//要操作的信号灯编号
short sem_op //0:等待,直到信号灯的值变成0,1:释放资源,V操作.-1:分配资源,p操作
short sem_flg ;//0,IPC_NOWAIT,SEM_UNDO
}
nops:要操作的信号灯个数