linux system ipc


原文链接: linux system ipc

一、无名管道

  • 无名管道时半双工的,就是对于一个管道来讲,只能读或者写
  • 无名管道只能在相关、有共同祖先的进程间使用
  • 一个fork或者exec调用创建的子进程继承了父进程的文件描述符

1,打开和关闭管道
int pipe(int filedes[2]);
//在你从一个管道中读写,管道必须存在
//如果成功建立管道,则会打开两个文件描述符,并把它们的值保存在一个数值
//第一个文件描述符用于读数据,第二个文件描述符用于写数据
//出错返回-1,同时设置errno
//关闭一个管道用close()函数
//不能两端进行读写

/读写无名管道例子/
int main()
{

int fd[2];//管道描述符
char buf[100];//存放管道收发数据
int len;//记录长度

pipe(fd);
memset(buf,0,sizeof(buf));//清空buf
int pid = fork();
if(pid == 0)
{
    close(fd[1]);//关闭写管道
    while(len = read(fd[0],buf,sizeof(buf) >0)//len大于
        {   
            write(STDOUT_FIFLNO,buf,len);  
        }

    close(fd[0]);

}
else
{
    close(fd[0]);//关闭读管道
    strcpy(buf,"hello world\n");
    write(fd[1],buf,sizeof(buf));
    close(fd[1]);
    waitpid(pid,NULL,0);


}
return 0;

}

二、有名管道(FIFO)

  • 有名管道是持久稳定的
  • 它们存在于文件系统中
  • 可以让无关联的进程之间通信

1,用shell命令建立有名管道mkfifo [option] name
#mkfifo fifo1 //创建一个有名管道
#cat < fifo1 //通过cat向管道读取数据
#ls > fifo1 //通过ls向管道输出数据

2,函数创建FIFO
int mkfifo(const char *pathname,mode_t mode)
//函数执行成功返回0,否则返回-1,并设置变量errno
int unlink(const char*pathname)
//删除fifo文件,执行成功返回0,否则返回-1,并设置变量errno

int main()
{
	mkfifo("fifo1",0666);
	//mode:rw-rw-rw为权限
	unlink("fifo1");
	return 0;
	
}

3,读写FIFO文件

//读FIFO例子
int main()
{
	int len = 0;
	char buf[100];
	memset(buf,0,sizeof(buf));
	int fd = open("fifo1",O_RDONLY);//只读方式
	while(len = read(fd[0],buf,sizeof(buf) >0)
	{
		printf("%s",buf);
		memset(buf,0,sizeof(buf));
	}
	close(fd);
	return 0;
	
}

//写FIFO例子
int main()
{

	char buf[100];
	memset(buf,0,sizeof(buf));
	int fd = open("fifo1",O_WRONLY);//只写方式
	while(1)
	{	
		read(STDIN_FIFLNO,buf,sizeof(buf));
		if(buf[0] == '0')//如果输入字符0,退出循环
			break;
		write(fd,buf,strlen(buf));
		memset(buf,0,sizeof(buf));
	}
	close(fd);
	return 0;
	
}

4,共享内存

  • 共享内存是内核处于在多个进程之间交换
    信息二留出的一块内存区
  • 如果段的权限设置恰当,每个要访问该段
    内存的进程都可以把它映像到自己的私有空间
  • 如果一个进程更新了段中的数据,其他进程也
    会立即看到更新
  • 由一个进程创建的段,也可以由另一个进程读写
  • 每个进程都把自己对共享进程内存的映像放到自
    己的内存空间

1)创建共享内存区

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key,size_t size,int shm_flg);
//参数key既可以是IPC_PRIVATE,也可以是ftok函数返回的一个关键字
//参数size指定段的大小。
//参数flag:八进制数,0XXX。转化为二进制权限
//shmget成功返回段标示符,失败返回-1。
int shmctl(id, IPC_RMID, 0);
//删除共享内存的函数

/创建共享内存区/
int main()
{

int shmid = shmget (IPC_PRIVATE,1024,0666);
if(shmid < 0)
    printf ("error\n");
else
    printf ("success\n");
return 0;
//在命令行执行ipcs -m 显示成功创建的共享内存信息
//nattch:已经附加到这个内存的进程数
//在命令行执行ipcrm shm shmid 删除共享内存

}

2)附加共享内存区
void *shmat (int shmid,const void *shmaddr,int shmfg );
//参数shmid是要附加的共享内存标示符
//总是把参数shmaddr设置为0
//参数shmflg可以为SHM_RDONLY,这意味着附加段是只读
//shmat成功返回被附加了段的地址,失败返回-1,并设置变量errno
int shmdt (const void *shmaddr );
//函数shmdt将附加在shmaddr的段从调用进程的地址空间分离出去,这个地址必须shmat返回

/附加,释放共享内存区/
int main(int argc,char *args[])
{

char* shmbuf;
int shmid = 0;
if(arg > 1)
{
    shmid = atoi(args[1]);//传入共享内存id
    shmbuf = shmat(shmid,0,0);
    sleep(60);
    shmdt(shmbuf);
}
return 0;

}

3)读写共享内存区
/附加,释放共享内存区/
int main(int argc,char *args[])
{

char* shmbuf;
int shmid = 0;
if(arg > 2)
{
    shmid = atoi(args[1]);//传入共享内存id
    shmbuf = shmat(shmid,0,0);
    if (atoi(args[2] == 1))//write shared mem
    {
        scanf ("%s\n",shmbuf);
    }
    if(atoi(args[2] == 2)//read shared mem
    {
        printf ("%s\n",shmbuf);
    }

    shmdt(shmbuf);
}
return 0;

}

`