1、管道(Pipe)
用的api函数有:pipe
示例:
//pipe.c
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
int main(int agrc ,char *argv[])
{
int fdset[2];
pid_t pid;
int r_num;
char buf_r[100];
pipe(fdset);
pid = fork();
if(pid == 0)
{
//子进程
printf("child progress running...\n");
//关闭写管道
close(fdset[1]);
//睡眠2s,等待父进程写
sleep(2);
if((r_num=read(fdset[0],buf_r,100))>0)
{
printf("%d numbers read from the pipe is %s\n",r_num,buf_r);
}
close(fdset[0]);
exit(0);
}
else
{
//父进程
printf("parent progress running...\n");
//关闭读管道
close(fdset[0]);
if(write(fdset[1],"hello,world!\n",13) != -1)
{
printf("parent write \'hello,world!\'\n");
}
close(fdset[1]);
waitpid(pid,NULL,0);
exit(0);
}
}
注意:fdset[0]为读端,fdset[1]写端。
2、有名管道(named pipe)
用的api函数有:mkfifo
示例:
//mkfifo_w.c
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define FIFO "/my_fifo"
int main(int argc, char *agrv[])
{
int fd;
int res = mkfifo(FIFO, 0777);
if(res == 0)
{
printf("FIFO created\n");
}
fd = open(FIFO, O_WRONLY|O_NONBLOCK, 0);
if(fd == -1)
{
perror("open");
exit(1);
}
if(argc < 2)
{
perror("argc");
exit(1);
}
if((write(fd,agrv[1],strlen(agrv[1])))== -1)
{
printf("The FIFO has not been read yet.Please try later\n");
}
else
printf("write %s to the FIFO\n");
close(fd);
exit(EXIT_SUCCESS);
}
//mkfifo_r.c
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
FIFO "/tmp/my_fifo"
//本程序从一个FIFO读数据,并把读到的数据打印到标准输出
//如果读到字符“Q”,则退出
int main(int argc, char** argv)
{
char buf_r[100];
int fd;
int nread;
if((mkfifo(FIFO, O_CREAT) < 0) && (errno != EEXIST))
{
printf("不能创建FIFO\n");
exit(1);
}
printf("准备读取数据\n");
fd = open(FIFO, O_RDONLY, 0);
if(fd == -1)
{
perror("打开FIFO");
exit(1);
}
while(1)
{
if((nread = read(fd, buf_r, 100)) == -1)
{
if(errno == EAGAIN) printf("没有数据\n");
}
//假设取到Q的时候退出
if(buf_r[0]=='Q') break;
buf_r[nread]=0;
printf("从FIFO读取的数据为:%s\n", buf_r);
sleep(1);
}
}
3、共享内存
用的api函数有:ftok、shmget、shmdt
示例:
//shm_com.h
#define TEXT_SZ 2048
struct shared_use_st
{
int written_by_you;
char some_text[TEXT_SZ];
};
#define KEY_PATH "etc/config.ini"
#define KEY_ID 111
//shm1.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "shm_com.h"
/*
* 程序入口
* */
int main(void)
{
key_t kyt;
int running=1;
void *shared_memory=(void *)0;
struct shared_use_st *shared_stuff;
int shmid;
kyt = ftok(KEY_PATH,KEY_ID);
/*创建共享内存*/
shmid=shmget(kyt,sizeof(struct shared_use_st),0666|IPC_CREAT);
if(shmid==-1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
/*映射共享内存*/
shared_memory=shmat(shmid,(void *)0,0);
if(shared_memory==(void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X\n",(int)shared_memory);
/*让结构体指针指向这块共享内存*/
shared_stuff=(struct shared_use_st *)shared_memory;
/*控制读写顺序*/
shared_stuff->written_by_you=0;
/*循环的从共享内存中读数据,直到读到“end”为止*/
while(running)
{
if(shared_stuff->written_by_you)
{
printf("You wrote:%s",shared_stuff->some_text);
sleep(1); //读进程睡一秒,同时会导致写进程睡一秒,这样做到读了之后再写
shared_stuff->written_by_you=0;
if(strncmp(shared_stuff->some_text,"end",3)==0)
{
running=0; //结束循环
}
}
}
/*删除共享内存*/
if(shmdt(shared_memory)==-1)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
//shm2.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "shm_com.h"
/*
* 程序入口
* */
int main(void)
{
int running=1;
key_t kyt;
void *shared_memory=(void *)0;
struct shared_use_st *shared_stuff;
char buffer[BUFSIZ];
int shmid;
kyt = ftok(KEY_PATH,KEY_ID);
/*创建共享内存*/
shmid=shmget(kyt,sizeof(struct shared_use_st),0666|IPC_CREAT);
if(shmid==-1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
/*映射共享内存*/
shared_memory=shmat(shmid,(void *)0,0);
if(shared_memory==(void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X\n",(int)shared_memory);
/*让结构体指针指向这块共享内存*/
shared_stuff=(struct shared_use_st *)shared_memory;
/*循环的向共享内存中写数据,直到写入的为“end”为止*/
while(running)
{
while(shared_stuff->written_by_you==1)
{
sleep(1);//等到读进程读完之后再写
printf("waiting for client...\n");
}
printf("Ener some text:");
fgets(buffer,BUFSIZ,stdin);
strncpy(shared_stuff->some_text,buffer,TEXT_SZ);
shared_stuff->written_by_you=1;
if(strncmp(buffer,"end",3)==0)
{
running=0; //结束循环
}
}
/*删除共享内存*/
if(shmdt(shared_memory)==-1)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
4、消息队列
用的api函数有:msgget、msgrcv、msgsnd、msgctl
示例:
/*msg.c*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFSZ 512
struct message{
long msg_type;
char msg_text[BUFSZ];
};
int main()
{
int qid;
key_t key;
int len;
struct message msg;
/*根据不同的路径和关键表示产生标准的key*/
if((key=ftok(".",'a'))== 1){
perror("ftok");
exit(1);
}
/*创建消息队列*/
if((qid=msgget(key,IPC_CREAT|0666))== 1){
perror("msgget");
exit(1);
}
printf("opened queue %d\n",qid);
puts("Please enter the message to queue:");
if((fgets((&msg)->msg_text,BUFSZ,stdin))==NULL){
puts("no message");
exit(1);
}
msg.msg_type = getpid();
len = strlen(msg.msg_text);
/*添加消息到消息队列*/
if((msgsnd(qid,&msg,len,0))<0){
perror("message posted");
exit(1);
}
/*读取消息队列*/
if(msgrcv(qid,&msg,BUFSZ,0,0)<0){
perror("msgrcv");
exit(1);
}
printf("message is:%s\n",(&msg)->msg_text);
/*从系统内核中移走消息队列。*/
if((msgctl(qid,IPC_RMID,NULL))<0){
perror("msgctl");
exit(1);
}
exit(0);
}
5、进程信号量
用的api函数有:semget、semop
示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define BUFFER_SIZE 2048
int main() {
pid_t pid;
int shmid;
char *shm_addr;
char flag[]="Parent";
char buff[BUFFER_SIZE];
// 创建当前进程的私有共享内存
if ((shmid=shmget(IPC_PRIVATE,BUFFER_SIZE,0666))<0) {
perror("shmget");
exit(1);
} else
printf("Create shared memory: %d.\n",shmid);
// ipcs 命令往标准输出写入一些关于活动进程间通信设施的信息
// -m 表示共享内存
printf("Created shared memory status:\n");
system("ipcs -m");
if((pid=fork())<0) {
perror("fork");
exit(1);
}else if (pid==0) {
// 自动分配共享内存映射地址,为可读可写,映射地址返回给shm_addr
if ((shm_addr=shmat(shmid,0,0))==(void*)-1) {
perror("Child:shmat");
exit(1);
}else
printf("Child: Attach shared-memory: %p.\n",shm_addr);
printf("Child Attach shared memory status:\n");
system("ipcs -m");
// 比较shm_addr,flag的长度为strlen(flag)的字符
// 当其内容相同时,返回0
// 否则返回(str1[n]-str2[n])
while (strncmp(shm_addr,flag,strlen(flag))) {
printf("Child: Waiting for data...\n");
sleep(10);
}
strcpy(buff,shm_addr+strlen(flag));
printf("Child: Shared-memory: %s\n",buff);
// 删除子进程的共享内存映射地址
if (shmdt(shm_addr)<0) {
perror("Child:shmdt");
exit(1);
}else
printf("Child: Deattach shared-memory.\n");
printf("Child Deattach shared memory status:\n");
system("ipcs -m");
}else{
sleep(1);
// 自动分配共享内存映射地址,为可读可写,映射地址返回给shm_addr
if ((shm_addr=shmat(shmid,0,0))==(void*)-1) {
perror("Parent:shmat");
exit(1);
}else
printf("Parent: Attach shared-memory: %p.\n",shm_addr);
printf("Parent Attach shared memory status:\n");
system("ipcs -m");
// shm_addr为flag+stdin
sleep(1);
printf("\nInput string:\n");
fgets(buff,BUFFER_SIZE-strlen(flag),stdin);
strncpy(shm_addr+strlen(flag),buff,strlen(buff));
strncpy(shm_addr,flag,strlen(flag));
// 删除父进程的共享内存映射地址
if (shmdt(shm_addr)<0) {
perror("Parent:shmdt");
exit(1);
}else
printf("Parent: Deattach shared-memory.\n");
printf("Parent Deattach shared memory status:\n");
system("ipcs -m");
// 保证父进程在删除共享内存前,子进程能读到共享内存的内容
waitpid(pid,NULL,0);
// 删除共享内存
if (shmctl(shmid,IPC_RMID,NULL)==-1) {
perror("shmct:IPC_RMID");
exit(1);
}else
printf("Delete shared-memory.\n");
printf("Child Delete shared memory status:\n");
system("ipcs -m");
printf("Finished!\n");
}
exit(0);
}