作业
- 通过无名管道,让两个子进程间完成相互通信工作
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
int pipefd[2]={0};
int ret=-1;
ret=pipe(pipefd);
if(-1==ret)
{
perror("pipe");
return -1;
}
pid_t pid=fork();
if(pid>0)
{
pid_t pid2=fork();
if(pid2>0)
{
waitpid(pid,NULL,0);
waitpid(pid2,NULL,0);
}
else if(0==pid2)
{
int iSign=0;
char caBuf[64]={'\0'};
while(1)
{
memset(caBuf,'\0',sizeof(caBuf));
if(0==iSign)
{
printf("child1-input data:");
scanf("%s",caBuf);
write(pipefd[1],caBuf,strlen(caBuf));
iSign=1;
}
else if(1==iSign)
{
read(pipefd[0],caBuf,sizeof(caBuf));
printf("child2 says:%s\n",caBuf);
iSign=0;
}
sleep(1);
}
}
else if(-1==pid2)
{
perror("second fork");
return -1;
}
}
else if(0==pid)
{
int iSign=0;
char caBuf[64]={'\0'};
while(1)
{
memset(caBuf,'\0',sizeof(caBuf));
if(0==iSign)
{
read(pipefd[0],caBuf,sizeof(caBuf));
printf("child1 says:%s\n", caBuf);
iSign=1;
}
else if(1==iSign)
{
printf("child2-input data:");
scanf("%s",caBuf);
write(pipefd[1],caBuf,strlen(caBuf));
iSign=0;
}
sleep(1);
}
}
else if(-1==pid)
{
perror("first fork");
return -1;
}
}
命名管道
- 创建一个命名管道
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#define FIFO_PATHNAME "myFifo"
int main(void)
{
int ret=-1;
ret=mkfifo(FIFO_PATHNAME,0777);
if(-1==ret)
{
if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
{
perror("mkfifo");
exit(EXIT_FAILURE);
}
}
printf("mkfifo is ok\n");
return 0;
}
- 在命名管道里插入数据
- 首先在一个终端运行写
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFO_PATHNAME "myFifo"
int main(void)
{
int ret=-1;
ret=mkfifo(FIFO_PATHNAME,0777);//创建一个管道文件
if(-1==ret)
{
if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
{
perror("mkfifo");
exit(EXIT_FAILURE);
}
}
printf("mkfifo is ok\n");
int fd=-1;
fd=open(FIFO_PATHNAME,O_WRONLY);
if(-1==fd)
{
perror("open");
exit(EXIT_FAILURE);
}
ret=write(fd,"hello world",11);//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
if(ret>0)
{
printf("write %d bytes to fifo\n",ret);
}
close(fd);
return 0;
}
- 在另外一个终端运行读的程序(这样写的程序才不会阻塞)
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFO_PATHNAME "myFifo"
int main(void)
{
int ret=-1;
ret=mkfifo(FIFO_PATHNAME,0777);//创建一个管道文件
if(-1==ret)
{
if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
{
perror("mkfifo");
exit(EXIT_FAILURE);
}
}
printf("mkfifo is ok\n");
int fd=-1;
fd=open(FIFO_PATHNAME,O_RDONLY);
if(-1==fd)
{
perror("open");
exit(EXIT_FAILURE);
}
char caBuf[64]={'\0'};
ret=read(fd,caBuf,sizeof(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
if(ret>0)
{
printf("%s\n",caBuf);
printf("read %d bytes from fifo\n",ret);
}
close(fd);
return 0;
}
- 管道中的数据,读取了之后,就已经没有数据了
- 管道两端相互通信
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFO_PATHNAME "myFifo"
int main(void)
{
int ret=-1;
ret=mkfifo(FIFO_PATHNAME,0777);//创建一个管道文件
if(-1==ret)
{
if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
{
perror("mkfifo");
exit(EXIT_FAILURE);
}
}
printf("mkfifo is ok\n");
int fd=-1;
fd=open(FIFO_PATHNAME,O_RDWR);
if(-1==fd)
{
perror("open");
exit(EXIT_FAILURE);
}
int iSign=0;
char caBuf[64]={'\0'};
while(1)
{
memset(caBuf, '\0', sizeof(caBuf));
if(iSign==0)
{
printf("1.please iput data\n");
scanf("%s",caBuf);
ret=write(fd,caBuf,strlen(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
if(ret==-1)
{
perror("write");
exit(EXIT_FAILURE);
}
iSign=1;
sleep(1);
}
else if(iSign==1)
{
ret=read(fd,caBuf,sizeof(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
if(ret==-1)
{
perror("read");
exit(EXIT_FAILURE);
}
printf("1.receive data:%s\n",caBuf);
iSign=0;
}
}
close(fd);
return 0;
}
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFO_PATHNAME "myFifo"
int main(void)
{
int ret=-1;
ret=mkfifo(FIFO_PATHNAME,0777);//创建一个管道文件
if(-1==ret)
{
if(EEXIST!=errno)//如果错误等于这个已经存在,我们可以直接运行
{
perror("mkfifo");
exit(EXIT_FAILURE);
}
}
printf("mkfifo is ok\n");
int fd=-1;
fd=open(FIFO_PATHNAME,O_RDWR);
if(-1==fd)
{
perror("open");
exit(EXIT_FAILURE);
}
int iSign=0;
char caBuf[64]={'\0'};
while(1)
{
memset(caBuf, '\0', sizeof(caBuf));
if(iSign==0)
{
printf("1.please iput data\n");
scanf("%s",caBuf);
ret=write(fd,caBuf,strlen(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
if(ret==-1)
{
perror("write");
exit(EXIT_FAILURE);
}
iSign=1;
sleep(1);
}
else if(iSign==1)
{
ret=read(fd,caBuf,sizeof(caBuf));//没有另一端进行读,所以一直阻塞在那里,直到有读的把他打开
if(ret==-1)
{
perror("read");
exit(EXIT_FAILURE);
}
printf("1.receive data:%s\n",caBuf);
iSign=0;
}
}
close(fd);
return 0;
}
总结管道的特点(只能在父子进程中使用)
- 单向通信
- 公共祖先
另一种通信方式(共享内存块)//shmget
- IPC:进程间的通信
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int shmid=-1;
//第一个参数:key_t key,相当于这块共享内存块的名字
//第二个参数:这个共享内存块的大小
shmid=shmget(0x1117,1024,IPC_CREAT);//它是十六进制的数据
if(-1==shmid)
{
perror("shmget");
exit(EXIT_FAILURE);
}
printf("shmget ok:%d\n",shmid);
return 0;
}
- 通过这种方法,则不用输入sudo ipcs -m,只需输入 ipcs -m就可以了,因为在程序中已经设置了他的权限
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int shmid=-1;
//第一个参数:key_t key,相当于这块共享内存块的名字
//第二个参数:这个共享内存块的大小
shmid=shmget(0x1204,1024,IPC_CREAT | S_IRUSR | S_IWUSR);//它是十六进制的数据
if(-1==shmid)
{
perror("shmget");
exit(EXIT_FAILURE);
}
printf("shmget ok:%d\n",shmid);
return 0;
}
shmop
- 创建一个共享内存块,再往里面插入数据,>再显
- 插入数据
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int shmid=-1;
//第一个参数:key_t key,相当于这块共享内存块的名字
//第二个参数:这个共享内存块的大小
shmid=shmget(0x1204,1024,IPC_CREAT | S_IRUSR | S_IWUSR);//它是十六进制的数据
if(-1==shmid)
{
perror("shmget");
exit(EXIT_FAILURE);
}
printf("shmget ok:id=%d\n",shmid);
void *pRet=NULL;
pRet=shmat(shmid,NULL,0);//只读打开或者读写打开为0,没有只写打开
if((void *)-1==pRet)//(void *)-1就是返回值的类型,表示错误的话返回这个
{
perror("shmat");
exit(EXIT_FAILURE);
}
char *pData="I want to sleep";
memcpy(pRet,pData,strlen(pData));//复制指指针变量
shmdt(pRet);//斩断与内存块的关联
return 0;
}
- 读取数据
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int shmid=-1;
//第一个参数:key_t key,相当于这块共享内存块的名字
//第二个参数:这个共享内存块的大小
shmid=shmget(0x1204,1024,IPC_CREAT | S_IRUSR | S_IWUSR);//它是十六进制的数据
if(-1==shmid)
{
perror("shmget");
exit(EXIT_FAILURE);
}
printf("shmget ok:id=%d\n",shmid);
void *pRet=NULL;
pRet=shmat(shmid,NULL,SHM_RDONLY);//只读打开或者读写打开为0,没有只写打开
if((void *)-1==pRet)//(void *)-1就是返回值的类型,表示错误的话返回这个
{
perror("shmat");
exit(EXIT_FAILURE);
}
char caBuf[32]={'\0'};
memset(caBuf,'\0',sizeof(caBuf));//最好初始化一下,以免存在野值
memcpy(caBuf,pRet,sizeof(caBuf));
printf("%s\n",caBuf);
shmdt(pRet);//斩断与内存块的关联
return 0;
}
shmctl 控制共享内存(要最后释放掉共享内存,则用)
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int shmid=-1;
//第一个参数:key_t key,相当于这块共享内存块的名字
//第二个参数:这个共享内存块的大小
shmid=shmget(0x1204,1024,IPC_CREAT | S_IRUSR | S_IWUSR);//它是十六进制的数据
if(-1==shmid)
{
perror("shmget");
exit(EXIT_FAILURE);
}
printf("shmget ok:id=%d\n",shmid);
void *pRet=NULL;
pRet=shmat(shmid,NULL,SHM_RDONLY);//只读打开或者读写打开为0,没有只写打开
if((void *)-1==pRet)//(void *)-1就是返回值的类型,表示错误的话返回这个
{
perror("shmat");
exit(EXIT_FAILURE);
}
char caBuf[32]={'\0'};
memset(caBuf,'\0',sizeof(caBuf));//最好初始化一下,以免存在野值
//数据读取之后,仍然保留在共享内存里面
//直到下一次写数据的时候被覆盖
memcpy(caBuf,pRet,sizeof(caBuf));
printf("%s\n",caBuf);
struct shmid_ds shmInfo;
//控制共享内存
//IPC_STAT:获得共享内存的信息,
shmctl(shmid,IPC_STAT,&shmInfo);
printf("shm size= %ld\n",shmInfo.shm_segsz);
shmctl(shmid,IPC_RMID,0);//消除内存空间
//shmdt(pRet);//斩断与内存块的关联
return 0;
}
- ipcrm +编号(删除某个内存);
- 将共享内存块映射到进程里
第三种通信方式 mmap(创建一个进程映射到虚拟地址)
- 将数据写入到这块内存空间
#include <sys/ipc.h>
#include <sys/mman.h>//mmap()
#include <sys/shm.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd=-1;
fd=open("test",O_RDWR);//"test"表示当前目录,
if(-1==fd)
{
perror("open");
exit(-1);
}
void *pRet=NULL;
pRet=mmap(NULL,32,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);//SHARED:其他进程也可以访问,10,偏移量
if((void *)-1==pRet)
{
perror("mmap");
exit(-1);
}
sprintf((char *)pRet,"%s %d %f\n","huihuidashadan",1024,3.14);//与memcpy一样,复制指针,即字符串//将数据格式化的写到这块内存空间里去
munmap(pRet,32);//取消映射
return 0;
}
//在test里面插入数据
//运行结果:插入到了test中,如果test里没有数据的话,就会报总线错误(核心已转储)
- 将数据读取出来
#include <sys/ipc.h>
#include <sys/mman.h>//mmap()
#include <sys/shm.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd=-1;
fd=open("test",O_RDWR);//"test"表示当前目录,
if(-1==fd)
{
perror("open");
exit(-1);
}
void *pRet=NULL;
pRet=mmap(NULL,32,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);//SHARED:其他进程也可以访问,10,偏移量
if((void *)-1==pRet)
{
perror("mmap");
exit(-1);
}
sprintf((char *)pRet,"%s %d %f\n","huihuidashadan",1024,3.14);//与memcpy一样,复制指针,即字符串//将数据格式化的写到这块内存空间里去
char caBuf[32]={'\0'};
int iData=0;
float fData=0;
sscanf(pRet,"%s%d%f",caBuf,&iData,&fData);//格式化输入数据
printf("%s %d %.2f\n",caBuf,iData,fData);
munmap(pRet,32);//取消映射
close(fd);
return 0;
}
//
第四种通信方式 (signal):信号
- A将信号传到内存里,B进程通过信号处理函数处理信号
信号的产生(硬件产生信号,软件产生信号)
- kill(),产生信号
/*kill()*/
#include<sys/types.h>
#include<signal.h>
/*fork()*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
pid_t pid=-1;
pid=fork();
if(pid>0)
{
while(1)
{
printf("I am parent,waiting child to kill me\n");
sleep(1);
}
}
else if(pid==0)
{
int i=5;
while(1)
{
if(0==i)
{
printf("i kill parent\n");
kill(getppid(),SIGKILL);//getppid()h获得父进程的进程号
break;
}
else
{
printf("still has %d second to kill parent\n",i);
sleep(1);
}
i--;
}
}
else if(pid==-1)
{
perror("fork");
exit(-1);
}
}
- 发送一个闹钟信号(alarm信号默认自杀)
#include<stdio.h>
#include<stdlib.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
//在指定的秒数之后,给本进程发送一个SIGALRM信号,该信号的默认处理是结束进程
alarm(5);
while(1)
{
printf("huihuidashabi\n");
sleep(1);
}
return 0;
}
raise,一个信号产生
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
int main()
{
int i=5;
while(1)
{
if(i==0)
{
raise(SIGKILL);
}
printf("ZZZZzzzzz~~~\n");
i--;
sleep(1);
}
}
自定义信号处理
- kill与stop不能以我们自定义的信号处理方式处理
#include<signal.h>//signal()
#include<stdio.h>
#include<string.h>
typedef void (*sighandler_t)(int);
void sigHandle(int sig)
{
if(SIGALRM==sig)
{
printf("catched sigalrm\n");
}
}
int main(void)
{
sighandler_t ret;
//指定信号的处理方式
//第一个参数:需要处理特殊处理的信号
//第二个参数:信号的处理方式
ret=signal(SIGALRM,sigHandle);
if(SIG_ERR==ret)
{
printf("signal failed\n");
return -1;
}
alarm(3);
while(1)
{
}
return 0;
}
- 设置一个信号,Ctrl+c,按下Ctrl+c,z则捕捉到信息
#include<signal.h>//signal()
#include<stdio.h>
#include<string.h>
typedef void (*sighandler_t)(int);
//使用SigHandle
void sigHandle(int sig)
{
if(SIGALRM==sig)
{
printf("catched sigalrm\n");
}
else if(SIGINT==sig)
{
printf("catched signal\n");
}
}
int main(void)
{
sighandler_t ret;
//指定信号的处理方式
//第一个参数:需要处理特殊处理的信号
//第二个参数:信号的处理方式
ret=signal(SIGALRM,sigHandle);
if(SIG_ERR==ret)
{
printf("signal failed\n");
return -1;
}
//SIG_DFL:使用该信号的默认处理动作来处理该信号
//SIG_IGN:忽略该信号
ret=signal(SIGINT,sigHandle)
if(SIG_ERR==ret)
{
printf("signal failed\n");
return -1;
}
alarm(3);
while(1)
{
}
return 0;
}
//按Ctrl+\键退出运行
#include<signal.h>//signal()
#include<stdio.h>
#include<string.h>
typedef void (*sighandler_t)(int);
//使用SigHandle
void sigHandle(int sig)
{
if(SIGALRM==sig)
{
printf("catched sigalrm\n");
}
else if(SIGINT==sig)
{
printf("catched signal\n");
}
}
int main(void)
{
sighandler_t ret;
//指定信号的处理方式
//第一个参数:需要处理特殊处理的信号
//第二个参数:信号的处理方式
ret=signal(SIGALRM,sigHandle);
if(SIG_ERR==ret)
{
printf("signal failed\n");
return -1;
}
//SIG_DFL:使用该信号的默认处理动作来处理该信号
//SIG_IGN:忽略该信号
ret=signal(SIGINT,SIG_IGN);
if(SIG_ERR==ret)
{
printf("signal failed\n");
return -1;
}
alarm(3);
while(1)
{
}
return 0;
}
//SIG_IGN:是忽略该信号,所以再按下Ctrl+c已经没有反应了
#include<signal.h>//signal()
#include<stdio.h>
#include<string.h>
typedef void (*sighandler_t)(int);
//使用SigHandle
void sigHandle(int sig)
{
if(SIGALRM==sig)
{
printf("catched sigalrm\n");
}
else if(SIGINT==sig)
{
printf("catched signal\n");
}
}
int main(void)
{
sighandler_t ret;
//指定信号的处理方式
//第一个参数:需要处理特殊处理的信号
//第二个参数:信号的处理方式
ret=signal(SIGALRM,sigHandle);
if(SIG_ERR==ret)
{
printf("signal failed\n");
return -1;
}
//SIG_DFL:使用该信号的默认处理动作来处理该信号
//SIG_IGN:忽略该信号
//ret=signal(SIGINT,sigHandle);
ret=signal(SIGINT,SIG_DFL);
if(SIG_ERR==ret)
{
printf("signal failed\n");
return -1;
}
alarm(3);
while(1)
{
}
return 0;
}
//SIG_DFL:使用该信号的默认处理动作来处理该信号