-
管道(Pipes)
- 单向通信channel
- 分为匿名管道(用于相关进程)和命名管道(用于无关进程)
-
信号(Signals)
- 用于发送简单消息
- 例如:SIGTERM, SIGKILL
-
消息队列(Message Queues)
- 允许进程通过发送和接收消息来交换数据
- 消息存储在队列中,直到接收进程检索它们
-
共享内存(Shared Memory)
- 多个进程共享同一块物理内存
- 最快的IPC方法,但需要同步机制
-
信号量(Semaphores)
- 用于同步进程操作和访问共享资源
- 可以防止竞态条件
-
套接字(Sockets)
- 可用于同一机器上的进程间通信,也可用于网络通信
- 支持全双工通信
-
文件(File)
- 进程可以通过读写同一个文件来交换数据
- 需要适当的文件锁定机制
-
内存映射文件(Memory-mapped Files)
- 将文件映射到进程的地址空间
- 可以像访问内存一样访问文件内容
-
远程过程调用(RPC)
- 允许一个进程调用另一个进程(可能在不同的机器上)的过程
- 常用于分布式系统
背景
为什么需要进程间通信
虚拟内存机制导致了进程只能访问自己的内存,如果想要其他进程的数据,就需要通信。
通信的目的有:同步、互斥、消息传递、资源共享
案例
- redis rdb、aof持久化,父子进程之间通信
- nginx master和worker/worker之间通信
- 界面与插件
- 连接不同主机
管道
cat file | grep "main"信号
$ <Ctrl+c> # 发送SIGINT信号消息队列
代码来自:https://developer.aliyun.com/article/297029
// sender.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>
#define MAX_TEXT 512
struct msg_st
{
long int msg_type;
char text[MAX_TEXT];
};
int main()
{
int running = 1;
struct msg_st data;
char buffer[BUFSIZ];
int msgid = -1;
//建立消息队列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
//向消息队列中写消息,直到写入end
while(running)
{
//输入数据
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
data.msg_type = 1; //注意2
strcpy(data.text, buffer);
//向队列发送数据
if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)
{
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
//输入end结束输入
if(strncmp(buffer, "end", 3) == 0)
running = 0;
sleep(1);
}
exit(EXIT_SUCCESS);
}// receiver.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
struct msg_st
{
long int msg_type;
char text[BUFSIZ];
};
int main()
{
int running = 1;
int msgid = -1;
struct msg_st data;
long int msgtype = 0; //注意1
//建立消息队列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
//从队列中获取消息,直到遇到end消息为止
while(running)
{
if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) == -1)
{
fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s\n",data.text);
//遇到end结束
if(strncmp(data.text, "end", 3) == 0)
running = 0;
}
//删除消息队列
if(msgctl(msgid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}信号量
共享内存
文件
MMAP
RPC
//
// example function to show how to make an RPC call to the coordinator.
//
// the RPC argument and reply types are defined in rpc.go.
//
func CallExample() {
// declare an argument structure.
args := ExampleArgs{}
// fill in the argument(s).
args.X = 99
// declare a reply structure.
reply := ExampleReply{}
// send the RPC request, wait for the reply.
// the "Coordinator.Example" tells the
// receiving server that we'd like to call
// the Example() method of struct Coordinator.
ok := call("Coordinator.Example", &args, &reply)
if ok {
// reply.Y should be 100.
fmt.Printf("reply.Y %v\n", reply.Y)
} else {
fmt.Printf("call failed!\n")
}
}