关于进程间通信杂谈

来源:互联网 发布:编程猫 李天驰 编辑:程序博客网 时间:2024/05/11 14:29

1

对于有名管道的创建必须是在home目录下,路径也写上,进入home后ls后发现黄色的文件就是,开启两个终端,在一个中端写入,另一个终端上vim进入里面显示。

2两个进程同时跑,有一个进程在vi里面创建才能跑,跑的图片如下,即使通过管道建立两个没有联系的进程中联系,并且一个写,一个读






























#include <unistd.h>

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<string.h>
#include <sys/ipc.h>
#include <sys/shm.h>


 








#define SIZE 1024


// 在管道读或者写入数据


int main1()
{
FILE *fp =popen("ps -ef","r");
if (fp==NULL)
{
perror("popen");
return -1;
}

char buf [SIZE]={0};
int ret=fread(buf,sizeof(char),SIZE-1,fp);

//此时不能写入ret,否则是段错误,成功读到数据缓冲区的个数

printf("读到的数据:\n  %s\n",buf);

FILE *fp2 =popen("grep a.out","w");
if (fp2==NULL)
{
perror("popen");
return -1;
}


fwrite (buf,sizeof(char),ret,fp2);

printf("写入完成\n");



pclose(fp);

fclose(fp2);

return 0;
}


// 单个进程之间的管道


int  main2()
{
int fd[2];

int ret =pipe(fd);
if (ret == -1)
{
perror("pipe");
return -1;
}
    

ret =write (fd[1],"hello",5);
printf("写入%d 个字节\n",ret);

char ch;

while(1)//这个死循环表示一个一个读取,但是最后可能没有0返还,并没有结束
{
ret =read(fd[0],&ch,1);
if (ret==-1)
{
perror("read");
return -1;
}
printf("读到的 %d字节:  %c\n",ret,ch);
}
//ret便是读到个数就是一个一个读的,ch储存在里面的字节

close(fd[0]);
close(fd[1]);

return 0;

}




void child_do1(int *fd)
{
//子进程通过管道读取父进程的数据,并且关闭自己的
//的写端
close(fd[1]);

char buf [SIZE];



while  (1)
{
int ret=read(fd[0],buf,SIZE-1);
 
if(ret==-1)
{
perror("read");
break;
}

 buf[ret]='\0';
 
 printf("子进程读到的%d 字节数据: %s\n",ret,buf);
}




close(fd[0]);
}




void father_do1(int *fd)
{
//父进程通过管道想子进程发送自己的数据,并且关闭
//自己的读端
close(fd[0]);


char buf[SIZE];

while (1)
{

       fgets(buf,SIZE,stdin);
  //表示从标准输入写入数据存在buf里面,这个参数就是
  int ret =write (fd[1],buf,strlen(buf));
  if (ret== -1)
 {
perror ("write");
return ;
 }
}


close(fd[1]);

}




int main3()
{
//建立管道
int fd[2];
int ret=pipe(fd);

if (ret==-1)
{

perror("pipe");
return -1;
}

//创建进程


pid_t pid =fork();




switch(pid)
{
case -1:
perror("fork");
break;

case  0:

child_do1(fd);
break;

default :
father_do1(fd);
break;

}

return 0;

}


void child_do2(int *fd)
{
//子进程通过管道读取父进程的数据,并且关闭自己的
//的写端
close(fd[1]);


int fd_write=open("2.ppt",O_WRONLY|O_CREAT,0777);

if(fd_write==-1)
{
perror("open");
return;
}
int ret;
char buf[SIZE];


while  (ret=read(fd[0],buf,SIZE-1))

{
//先从管道里读取数据到缓冲区
 
buf[ret]='\0';
// 从管道读取数据,如果管道没有数据可读,read会阻塞,如果管道的写段被关闭,read
// 返回0;
if(ret==-1)
{
perror("read");
break;
}

 write(fd_write,buf,ret);
 //先把缓冲区里的数据读到你创建的文件2.ppt里
 
  
}


printf("复制完成\n");

close(fd_write);
close(fd[0]);
}




void father_do2 (int *fd)
{
//父进程通过管道想子进程发送自己的数据,并且关闭
//自己的读端
close(fd[0]);


int fd_read=open("1.ppt",O_RDONLY);

if(fd_read==-1)
{
perror("read");
return;
}

int ret;
char buf[SIZE];
while (ret = read(fd_read,buf,SIZE))
{

buf[ret]='\0';
if (ret==-1)
{
perror("read");
break;
}



 write(fd[1],buf,ret);
  
}

close(fd_read);
close(fd[1]);

}




int main4()
{
//建立管道
int fd[2];
int ret=pipe(fd);

if (ret==-1)
{

perror("pipe");
return -1;
}

//创建进程


pid_t pid =fork();

switch(pid)
{
case -1:
perror("fork");
break;

case  0:

child_do2(fd);
break;

default :
father_do2(fd);
break;

}

return 0;

}


void child_do(int *fd)
{
close(fd[1]);
close(fd[0]);
//将孩子进程的读写端全部关闭
}


void father_do(int *fd)
{
close(fd[0]);

printf ("等待子进程关闭读端\n");
sleep(2);

// 所有读端都关闭了,写端继续往管道写入数据
// 如果管道所有的读端都被关闭,继续写数据系统默认的操作是使程序退出
write (fd[1], "hello", 5);


printf ("11111111111111111111111111111111\n");
// 关闭写端

close(fd[1]);
//说明管道是一端读一端写的,先进先出,关闭任何一段将无法读写数据
}




int main5()
{
//建立管道
int fd[2];
int ret=pipe(fd);

if (ret==-1)
{

perror("pipe");
return -1;
}

//创建进程


pid_t pid =fork();

switch(pid)
{
case -1:
perror("fork");
break;

case  0:

child_do(fd);
break;

default :
father_do(fd);
break;

}

return 0;

}






int main6()
{
int ret = mkfifo("/home/wode", 0777);

//必须在home目录下,不能在共享文件下,可能就是管道连接
//两个目录,进入home里面你就会看见
if (ret == -1)
{
perror ("mkfifo");
return -1;
}

return 0;
}


int main7()
{
int fd=open("/home/wode",O_WRONLY);
if(fd== -1)
{
perror("open");
return -1;
}

char buf[SIZE];
while(1)
{
fgets(buf,SIZE,stdin);

write(fd,buf,strlen(buf));//将标准输入的内容打进以前创建的有名管道里
}

//从朴准输入里输入,打开两个终端,你会发现home目录下显示
//share里面输入的内容

return 0;

}


int main8()
{
int fd = open("/home/mkfifo", O_RDWR);
if (fd == -1)
{
perror ("mkfifo");
return -1;
}

char buf[SIZE];
while (1)
{

int ret = read (fd, buf, SIZE);
buf[ret] = '\0';
sleep(1);

printf ("读到 %d 字节: %s\n", ret, buf);
}

return 0;
}


// 将七八两个放在两个终端上联系,并且用两个gcc,你会发现两个进程对同一个
//程序控制,这就是所谓的有名管道之间的联系


//但是在终端上进去才能建立两者之间的循环,具体原因我也不知道


typedef struct _shm
{
int flag;
char msg[256];
}SHM;//定义一个结构体共享内存


int main9()
{
// 1、创建或者获取一个共享内存
int shmid = shmget((key_t)1234, sizeof(SHM), 0666 | IPC_CREAT);
if (shmid == -1)
{
perror ("shmget");
return -1;
}

// 2、将共享内存映射到当前的进程空间
SHM* pshm = (SHM*)shmat(shmid, NULL, 0);

//强制装换为共享内存的类型,并且第一个参数是由shmget返回的
//共享内存标识符
if(pshm == (SHM*)-1)
{
perror ("shmat");
return -1;
}

strcpy (pshm->msg, "hello");

printf("共享内存里写入:  %s\n",pshm->msg);

// 解除共享内存映射,解除是值当前进程不能再使用共享内存
shmdt(pshm);
//参数是有shmat映射到进程里面的共享指针


shmctl(shmid, IPC_RMID, NULL);
//第一个参数是共享内存标示符,第二个参数是删除,第三个是一个指针,指向共享内存
//模式和访问的结构,此时设置为空



return 0;
}


int main()
{
// 1、创建或者获取一个共享内存
int shmid = shmget((key_t)1234, sizeof(SHM), 0666 | IPC_CREAT);
if (shmid == -1)
{
perror ("shmget");
return -1;
}


sleep(10);

// 2、将共享内存映射到当前的进程空间
SHM* pshm = (SHM*)shmat(shmid, NULL, 0);
if(pshm == (SHM*)-1)
{
perror ("shmat");
return -1;
}

printf ("%s\n", pshm->msg);
// 就是进入共享内存里面





return 0;
}