每个进程的用户地址空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享的,所以进程之间要通信必须通过内核
一、管道
匿名管道通过 fork()
系统调用创建的子进程与父进程之间的通信通道,另外还可以通过以下操作实现非父子进程之间的通信
cat xxx | wc -l
命名管道是一种特殊类型的文件,它允许进程之间进行通信。与匿名管道不同,命名管道在文件系统中有一个相关的路径名,因此允许不相关的进程通过该路径名进行通信
mkfifo my_pipe
echo "Hello, this is a message from the writer!" > my_pipe
cat < my_pipe
特点:
1. 一次性通信: 管道通常用于一次性的通信,一旦数据被读取,它们就会被丢弃。
2. 单向通信: 管道是单向的,不能直接支持双向通信,需要建立多个管道来实现双向通信。
二、消息队列
消息队列是一种进程间通信的方式,允许不同进程之间通过在共享的消息队列中发送和接收消息来进行通信。消息队列允许进程异步地进行通信,即发送方将消息放入队列后即可继续执行,而不需要等待接收方立即接收消息。
特点
1. 异步通信: 发送方和接收方可以以异步的方式进行通信,不需要即时的相互等待。
2. 消息队列不适合比较大数据的传输,因为在内核中每个消息体都有一个最大长度的限制
3. 消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销
三、共享内存
共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外一个进程马上就能看到了,都不需要拷贝来拷贝去,传来传去,大大提高了进程间通信的速度。
四、信号量
信号量是一种用于进程同步和互斥的机制,它允许多个进程之间通过对共享的信号量进行操作来实现对共享资源的访问控制。信号量通常用于解决多个进程竞争共享资源的并发访问问题,可以保证多个进程之间的数据一致性和正确性。
信号量通常具有两种操作:
1. P(等待)操作: 这个操作会将信号量减一,相减后信号量如果小于0,则表示资源已经被占用了,进程需要阻塞等待;如果大于等于0,则说明还有资源可用,进程可以正常执行。
2. V(释放)操作: 这个操作会将信号量加一,相加后信号量如果小于等于0,则表明当前有进程阻塞,于是会将该进程唤醒;如果大于0,则表示当前没有阻塞的进程。
信号量通常与其他进程间通信机制(如共享内存)结合使用,以实现对共享资源的互斥访问和同步操作。使用信号量可以避免进程之间竞争共享资源而导致的数据不一致或错误。
五、信号
信号通常由操作系统或进程内部的异常处理机制发送,可以用于处理如下事件:
1.外部事件: 例如用户按下Ctrl+C中断键,操作系统会向前台进程发送一个 SIGINT 信号,通知进程终止执行。
2.内部事件: 例如某个进程访问了非法内存地址,操作系统会向该进程发送一个 SIGSEGV 信号,通知进程出现了段错误。
3.其他进程的请求: 一个进程可以通过系统调用(如 kill 函数)向另一个进程发送信号。
六、Socket
前面提到的管道、消息队列、共享内存、信号量和信号都是在同一台主机上进行进程间通信,那要想跨网络与不同主机上的进程之间通信,就需要 Socket 通信了。
实际上,Socket 通信不仅可以跨网络与不同主机的进程间通信,还可以在同主机上进程间通信。
根据创建 socket 类型的不同,通信的方式也就不同:
1. 实现 TCP 字节流通信: socket 类型是 AF_INET 和 SOCK_STREAM;
2. 实现 UDP 数据报通信:socket 类型是 AF_INET 和 SOCK_DGRAM;
3. 实现本地进程间通信: 「本地字节流 socket 」类型是 AF_LOCAL 和 SOCK_STREAM,「本地数据报 socket 」类型是 AF_LOCAL 和 SOCK_DGRAM。另外,AF_UNIX 和 AF_LOCAL 是等价的,所以 AF_UNIX 也属于本地 socket;