程序同步-管道和IPC
阿新 • • 發佈:2018-12-22
參考文章:https://blog.csdn.net/bit_clearoff/article/details/55105816
管道是程序間通訊的方式之一,是在程序之間建立一個實現資料流通的通道,用來快取要傳輸的資料。
每個管道有兩個檔案描述符,寫和讀。
例:父子程序通訊,關閉無關的檔案描述符,子->父,子關閉讀,父關閉寫。
管道特點:
1.管道沒有名字。
2.管道是半雙工的,資料單向流動,雙向通訊需要兩個管道。
3.只能擁有有親屬關係的程序之間。
4.單獨構成檔案系統,並且只存在記憶體中。
5.緩衝區大小有限。
6.資料的寫入和讀出:一個程序寫入的從管道另一邊讀出,寫入在管道末尾,讀出在緩衝區頭部。
7.管道傳送的是無格式位元組流。
管道建立
void pipe_init() { /* 通過pipe建立一個管道,引數是一個int型pipefd[2],分別代表讀和寫。 成功返回0,反之-1。 */ int fd[2]; char readbuffer[20]; char writebuffer[]="hello world"; int temp=pipe(fd); if(temp<0) { cout<<"pipe creat error"<<endl; exit(0); } write(fd[1], writebuffer, sizeof(writebuffer));//管道寫入資料 read(fd[0], readbuffer, sizeof(writebuffer));// 讀出 size和write一樣 cout<<"管道讀出的資料:"<<readbuffer<<endl;//輸出讀到的資料 cout<<"管道的讀檔案符fd[0]:"<<fd[0]<<" 管道的寫檔案符fd[0]:"<<fd[1]<<endl; //結束時要關閉檔案描述符 close(fd[0]); close(fd[1]); }
父子程序之間通訊
(不知道為啥必須在if裡面寫fork 如果在外面建立pid read讀區會出錯誤)
void pid_pipe1()//在父子程序中進行管道通訊 父程序讀 子程序寫 { int fd[2]; //char readbuffer[20]; //char writebuffer[]="helloworld"; pid_t pid; //pid=fork(); int pe=pipe(fd); if(pe<0) { cout<<"pipe failed"<<endl; exit(1); } if(fork()==0)//child 不知道為啥必須在if裡面寫fork 如果在外面建立pid read讀區會出錯誤 { char writebuffer[12]="hello world"; close(fd[0]);//子程序寫操作 把讀關了 write(fd[1], writebuffer, sizeof(writebuffer));//管道寫入資料 //write(fd[1], &writebuffer, 1);//管道寫入資料 } else//father { sleep(1); close(fd[1]);//父程序寫操作 把寫關了 //char readbuffer[20]; char readbuffer[12]; read(fd[0], readbuffer, 12);// 讀出 size和write一樣 cout<<"父程序中,管道讀出的資料:"<<(readbuffer)<<endl;//輸出讀到的資料 //printf("%s",readbuffer); } exit(0); }
Linux的命名管道
命名管道和管道一樣,都是實實在在的檔案,但兩者的區別在於,命名管道又一個路徑名與之關聯。管道的檔案是不公開的,管道通訊只是存在於有親屬關係的程序之中,但是和建立命名管道的程序沒有親屬關係的程序,只要可以訪問路徑,兩個程序就可以實現通訊。
命名管道的工作方式
1 命名管道由shell建立,將資料從一條管道傳遞到另一條,無需建立中間臨時檔案。
2 用於客戶程序和服務程序的應用程式,在客戶程序和伺服器程序之間傳遞資料。
ps:由於命名管道是檔案格式,同一個名字的檔案建立成功之後就不能再建立了。
void fun1(int argc, const char * argv[])//使用mkfifo函式建立命名管道
{
mode_t mode=0755;//檔案許可權設定
if(argc!=2)
{
// cout<<"請輸入正確的檔案引數"<<endl;
//exit(0);
}
//成功返回0 反之返回-1 第一個引數是命名管道的檔案路徑名字
if(mkfifo("mingmingguandao", mode)==0)
{
cout<<"命名管道建立成功"<<endl;
//cout<<"建立失敗"<<endl;
//exit(1);
}
else
{
cout<<"建立失敗"<<endl;
exit(1);
}
}
建立失敗的原因是已經建立成功,檔案已經存在。
匿名管道(普通管道)完整程式和參考程式碼
//
// main.cpp
// Linux程序同步-管道和IPC
//
// Created by 藍貓 on 2018/11/8.
// Copyright © 2018年 藍貓. All rights reserved.
//
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
/*
管道是程序間通訊的方式之一,是在程序之間建立一個實現資料流通的通道,用來快取要傳輸的資料。
每個管道有兩個檔案描述符,寫和讀。
例:父子程序通訊,關閉無關的檔案描述符,子->父,子關閉讀,父關閉寫。
管道特點:
1.管道沒有名字。
2.管道是半雙工的,資料單向流動,雙向通訊需要兩個管道。
3.只能擁有有親屬關係的程序之間。
4.單獨構成檔案系統,並且只存在記憶體中。
5.緩衝區大小有限。
6.資料的寫入和讀出:一個程序寫入的從管道另一邊讀出,寫入在管道末尾,讀出在緩衝區頭部。
7.管道傳送的是無格式位元組流。
*/
void pipe_init()
{
/*
通過pipe建立一個管道,引數是一個int型pipefd[2],分別代表讀和寫。
成功返回0,反之-1。
*/
int fd[2];
char readbuffer[20];
char writebuffer[]="hello world";
int temp=pipe(fd);
if(temp<0)
{
cout<<"pipe creat error"<<endl;
exit(0);
}
write(fd[1], writebuffer, sizeof(writebuffer));//管道寫入資料
read(fd[0], readbuffer, sizeof(writebuffer));// 讀出 size和write一樣
cout<<"管道讀出的資料:"<<readbuffer<<endl;//輸出讀到的資料
cout<<"管道的讀檔案符fd[0]:"<<fd[0]<<" 管道的寫檔案符fd[0]:"<<fd[1]<<endl;
//結束時要關閉檔案描述符
close(fd[0]);
close(fd[1]);
}
void pid_pipe1()//在父子程序中進行管道通訊 父程序讀 子程序寫
{
int fd[2];
//char readbuffer[20];
//char writebuffer[]="helloworld";
pid_t pid;
//pid=fork();
int pe=pipe(fd);
if(pe<0)
{
cout<<"pipe failed"<<endl;
exit(1);
}
if(fork()==0)//child
{
char writebuffer[12]="hello world";
close(fd[0]);//子程序寫操作 把讀關了
write(fd[1], writebuffer, sizeof(writebuffer));//管道寫入資料
//write(fd[1], &writebuffer, 1);//管道寫入資料
}
else//father
{
sleep(1);
close(fd[1]);//父程序寫操作 把寫關了
//char readbuffer[20];
char readbuffer[12];
read(fd[0], readbuffer, 12);// 讀出 size和write一樣
cout<<"父程序中,管道讀出的資料:"<<(readbuffer)<<endl;//輸出讀到的資料
//printf("%s",readbuffer);
}
exit(0);
}
int fun1()
{
int filedes[2];
//pid_t pid;
//pid=fork();
char buf[10];
char out[10];
pipe(filedes);
if(fork() ==0)
{
close(filedes[0]);//子程序寫操作 把讀關了
sprintf(buf,"%s","ab");
write(filedes[1],buf,sizeof(buf));
}
else
{
close(filedes[1]);//子程序寫操作 把讀關了
read(filedes[0],out,sizeof(buf));
printf("%s\n",out);
}
return 0;
}
int fun2()
{
//create pipe
int fd[2]={0,0};
if(pipe(fd)!=0){
//create false
perror("pipe");
exit(1);
}
// pipe create success
pid_t id=fork();
if(id==0){
//child -->write fd[1]
printf("Child\n");
sleep(2);
const char* msg="Hello,leap\n";
close(fd[0]);
int count=3;
while(count--){
ssize_t size=write(fd[1],msg,strlen(msg));
printf("size:%d\n",size);
//if(count--){
// sleep(1);
//}
sleep(1);
printf("child is writing...\n");
}
close(fd[1]);
exit(0);
}
else{
//father -->read fd[0]
printf("Father\n");
sleep(2);
close(fd[1]);
char buf[1024];
int count=3;
while(1){
ssize_t Len=read(fd[0],buf,1024);
//printf("Len::%d\n",Len);
printf("Father is reading...\n");
if(Len>0){
//read success
buf[Len]='\0';
printf("child say:%s",buf);
}
else if(Len==0){
//read end of file
printf("Read the end of pipe\n");
break;
}
else{
perror("read");
exit(1);
}
}
close(fd[0]);
int status=0;
pid_t _pid=waitpid(id,&status,0);
if(_pid==id){
printf("Wait success for child\n");
printf("Exit code:%d,Exit signal:%d\n",(status>>8)&0xff,status&0xff);
}
else{
perror("wait");
}
exit(0);
}
return 0;
}
int main(int argc, const char * argv[])
{
pid_pipe1();
//fun2();
return 0;
}