Linux 进程间通信

1、无名管道

/*无名管道双向通信试验*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
    int fd_fs[2],fd_sf[2];
    if(pipe(fd_fs) || pipe(fd_sf)) /*创建管道*/
    {
        perror("pipe init error.");	
        return -1;
    }
    pid_t pid = fork();
    if(pid < 0)
    {
     	error("fork error.");
        return -1;
    }
    else if(pid == 0)
    {
        close(fd_fs[1]);
        close(fd_sf[0]);
        char buf_recs[30] = {0};
        /*son receive*/
        if(!read(fd_fs[0],buf_recs,sizeof(buf_recs)))
        {
            perror("read error.");
            close(fd_fs[0]);
            return -1;
        }
        char buf_sf[30] = "hello father";
        if(!write(fd_sf[1],buf_sf,sizeof(buf_sf)))  /*son send*/
        {
            perror("son sen error.");
            close(fd_sf[1]);
            return -1;
        }
        printf("son receive:%s\n",buf_recs);
        close(fd_fs[0]);
        close(fd_sf[1]);

    }else{
        /*father send*/
        close(fd_fs[0]);
        close(fd_sf[1]);
        char buf_fs[30] = "hello son.";
        char buf_recf[30] = {0};
        if(!write(fd_fs[1],buf_fs,sizeof(buf_fs)))  /*father send*/
        {
            perror("write error.");
            close(fd_fs[1]);
        return -1;
        }
        if(!read(fd_sf[0],buf_recf,sizeof(buf_recf)))   /*father receive*/
        {
            perror("father receive error.");
            close(fd_sf[0]);
            return -1;
        }
        printf("father receive :%s\n",buf_recf);
        close(fd_fs[1]);
        close(fd_sf[0]);
        /*father receive*/
    } 
    return 0;
}

2、有名管道

头文件:

#include <unistd.h>
#include <fcntl.h>
int mkfifo(const char*filename,mode_t mode);

特点:
(1)能够用于任何进程间通信(同一主机)
(2)半双工通信
(3)使用文件IO进程操作
(4)有管道文件,但实际操作的是内核中的管道
管道读写注意点:
(1)当管道中无数据时,该管道会阻塞。
(2)如果读进程不读走管道中的数据,写操作将一直阻塞
(3)只有在管道的读存在时才有意思,否则,将传来内核SIGPIPE的信号(通常是Broken pipe)
无名管道示例程序

/*fifo_w.c  write*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main()
{
	/*创建有名管道*/
	int ret = mkfifo("myfifo","0666");
	if(ret < 0 errno != EEXIST)  //忽略管道文件已经存在的情况
	{
		perror("mkfifo error.");
		return -1;
	}
	/*open*/
	int fd = open("myfifo",O_ERONLY);
	if(fd < 0)
	{
		perror("open error.");
		return -1;
	}
	char buf[100] = {0};
	fgets(buf,sizeof(buf),stdin);

	ret = write(fd,buf,sizeof(buf));
	if(ret < 0)
	{
		perror("write error.");
		return -1;
	} 
	close(fd);
	return 0;
} 

/*fifo_r.c  read*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main()
{
	/*创建有名管道*/
	int ret = mkfifo("myfifo","0666");
	if(ret < 0 errno != EEXIST)  //忽略管道文件已经存在的情况
	{
		perror("mkfifo error.");
		return -1;
	}
	/*open*/
	int fd = open("myfifo",O_RDONLY);
	if(fd < 0)
	{
		perror("open error.");
		return -1;
	}
	char buf[100] = {0};
	//fgets(buf,sizeof(buf),stdin);

	ret = read(fd,buf,sizeof(buf));
	if(ret < 0)
	{
		perror("read error.");
		return -1;
	} 
	printf("%s\n", buf);
	close(fd);
	return 0;
} 

总结:
(1)不管是有名管道还是无名管道,一个管道只能实现单向通信,要实现双向通信,就必须在创建一个管道。
(2)不管是又名管道还是无名管道,本质都是内核空间

3、信号

(1)信号是一种异步通信方式
(2)信号都是由内核产生的
kill :可以给任何进程发信号 kill(pid,信号)
reise : 只能给自己发 reise(信号)
信号安装:

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
//signum :指定信号
//handler : 
//(1)SIG_IGN :忽略该信号
//(2)SIG_DFL : 采用系统默认方式处理信号
//(3)定义信号处理函数
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char const *argv[])
{
	/* 信号安装 */
	signal(SIG_INT,SIG_IGN);
	while(1)
	{
		printf("helloworld\n");
	}
	return 0;
}

pause函数:pause() : 挂起当前进程,知道收到信号为止
用法:

#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
	pause();  挂起
	printf("hello world\n");
	return 0;
}

alarm函数

unsigned int alarm(unsigned int seconds)

seconds:指定秒数。

4、共享内存

共享内存是一种最为高效的进程间通信方式。
IPC对象:
1、由内核创建,存在于内核中
2、通过ID号进行访问
共享内存示例代码

/*共享内存进程write*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
int int main(int argc, char const *argv[])
{
	/* 得到key值 
	*key_t ftok(const char *pathname,int proj_pid)
	*/
	key_t key = ftok("/tmp",68);  //随意传参,两个进程一样1-255
	if(key < 0)
	{
		perror("ftok error.");
		return -1;
	}
	/*创建共享内存*/ 
	/*int shmget(key )*/
	int shmID = shmget(key,100,IPC_CREAT | 0666);
	if(shmID < 0)
	{
		perror("shmget error.");
		return -1;
	} 
	/*共享内存映射*/
	void *p = shmat(shmID,NULL,0);
	if((void *)-1 == p)
	{
		perror("shmat error.");
		shmctl(shmID,IPC_RMID,NULL);
		return -1;
	}

	/*操作*/
	puts("please input:");
	fgets(p,100,stdin); 
	/*取消映射*/
	shmdt(p);
	return 0;
}


/*共享内存进程read*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
int int main(int argc, char const *argv[])
{
	/*****************************************************/
	/* 得到key值 
	*key_t ftok(const char *pathname,int proj_pid)
	*/
	key_t key = ftok("/tmp",68);  //随意传参,两个进程一样1-255
	if(key < 0)
	{
		perror("ftok error.");
		return -1;
	}
	/*创建共享内存*/ 
	/*int shmget(key )*/
	int shmID = shmget(key,100,IPC_CREAT | 0666);
	if(shmID < 0)
	{
		perror("shmget error.");
		return -1;
	} 
	/*共享内存映射*/
	char *p = (void *)shmat(shmID,NULL,0);
	if((void *)-1 == p)
	{
		perror("shmat error.");
		shmctl(shmID,IPC_RMID,NULL);
		return -1;
	}
	puts(p);
    //取消映射
    shmdt(p); 
    //删除共享内存
    shmctl(shmId, IPC_RMID, NULL);
	return 0;
}

消息队列

(1)消息队列是IPC对象的一种
(2)消息队列由消息队列ID来唯一标识
(3)可以添加消息读取消息
*(4)消息队列可以安装类型来发送/接受消息
(5) 存在与内核中

/*msg_send*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct msgbuf
{
	long msgtype;
	char data[20];
};
int main(int argc, char const *argv[])
{
	// 创建消息
	key_t key = ftok("./",89);
	if(key < 0)
	{
		perror("ftok error.");
		return -1;
	}
	int msgID = msgget(key,IPC_CREAT | 0666);
	if(msgID  < 0)
	{
		perror("msgget error.");
		return -1;
	}
	// 添加消息
	struct msgbuf buf = {1,"hello"};
	int ret = msgsnd(msgID,&buf,sizeof(buf.data),0);
	if(ret < 0)
	{
		perror("msgsnd error.");
		msgctl(msgID,IPC_RMID,NULL);
		return -1;
	}
	puts("send ok");
	return 0;
}


/*msg_receive*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
struct msgbuf
{
	long msgtype;
	char data[20];
};
int main(int argc, char const *argv[])
{
	// 创建消息
	ey_t key = ftok("./",89);
	if(key < 0)
	{
		perror("ftok error.");
		return -1;
	}
	int msgID = msgget(key,IPC_CREAT | 0666);
	if(msgID  < 0)
	{
		perror("msgget error.");
		return -1;
	}
	// 读取消息
	struct msgbuf buf = {0};
	int ret = msgrcv(msgID,&buf,sizeof(buf),0,0);
	if(ret < 0)
	{
		perror("rcv error.");
		msgctl(msgID,IPC_REMID,NULL);
		return -1;
	}
	printf("%s\n", buf.data);

	// 删除消息
	msgctl(msgID,IPC_REMID,NULL);
	return 0}

进程间通信总结

通信方式
(1)无名管道
(2)有名管道
(3)信号
(4)共享内存
(5)消息队列
(6)信号量

注意:以上都是同一台主机的进程间通信。
由数据交换的通信方式:无名管道 有名管道 共享内存 消息队列
信号:一种异步通信机制
信号量:同步机制
(1)无名信号量:多用于线程间
(2)有名信号量:进程间

不同主机间的通信方式:只有套接字

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值