进程间通信
进程间通信方式
- 普通文件
- 管道(pipe)
- 信号(signal)
- 共享内存(shared memory)
- socketpair
- socket
普通文件
普通文件可能是我们接触的最早的进程间通信的方式了,只是在刚接触时,并不知道或了解进程是什么。多个进程可以通过读写同一个文件达到通信的目的。
管道
管道是以半双工(数据可以在一个信号载体的两个方向上传输,但是不能同时传输)机制来通信的,分为匿名管道可有名管道;匿名管道只能用于有亲缘关系的进程,有名管道能用于有亲缘关系和无亲缘关系的进程。
// 匿名管道,模拟全双工
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(argc, char* argv[])
{
int fd_first[2], fd_second[2];
if( !(!pipe(fd_first) && pipe(fd_second)) ){
perror("pipe");
return -1;
}
pid_t pid = fork();
if(pit == 0){ // Child process
close(fd_first[0]); close(fd_second[1]);
char msg[128] = "Hi, Parant process ...";
write(fd_first[1], msg, strlen(msg) + 1);
memset(msg, 0, sizeof(msg));
read(fd_second[0], msg, sizeof(msg));
printf("Message from Parent: %s\n", msg);
}else{
close(fd_first[1]); close(fd_second[0]);
char msg[128] = {0};
read(fd_first[0], msg, sizeof(msg));
printf("Message from Child: %s\n", msg);
memset(msg, 0, sizeof(msg));
strcpy(msg, "Hi, Child ...");
write(fd_second[1], msg, strlen(msg) + 1);
wait(NULL);
}
return 0;
}
// 有名管道 ipc_fifo_write.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
int ret = mkfifo("filename.ff", 0755);
if(ret != 0){
perror("mkfifo");
exit(-1);
}
int fd = open("filename.ff", O_WRONLY);
if(fd == -1){
perror("open");
exit(-1);
}
char msg[128] = "Hello world!";
ret = write(fd, msg, strlen(msg) + 1); // Write to fifo.
if(ret < 0){
perror("write");
}
close(fd);
return 0;
}
// ipc_fifo_read.c
int main()
{
int fd = open("filename.ff", O_RDONLY);
if(fd == -1){
perror("open");
exit(-1);
}
char msg[128] = {0};
int ret = read(fd, msg, sizeof(msg));
if(ret > 0){
printf("Message from FIFO : %s\n", msg);
}
perror("read");
close(fd);
return 0;
}
共享内存
// 匿名共享
int main()
{
void* shm = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANOYMOUS, -1,0);
if(shm == MAP_FAILED){
perror("mmap");
return 0;
}
pid_t pid = fork();
if(pid == 0){
*(int*)shm = 100;
}else{
sleep(1);
printf("From parent : %d\n", *(int*)shm);
wait(NULL);
}
munmap(shm, 1024);
return 0;
}
// 有名共享
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int fd = shm_open("/test.shm", O_RDWR, 0755);
if(fd < 0){
fd = shm_open("/test.shm", O_RDWR | O_CREAT, 0755);
if(fd < 0){
perror("shm_open");
return -1;
}
ftruncate(fd, 4096);
}
char* shm = (char*)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
pid_t pid = fork();
if(pid == 0){
strcmp(shm, "Hello world\n");
}else{
sleep(1);
printf("From shared memory : %s\n", shm);
wait(NULL);
}
munmap(shm);
return 0;
}
socketpair
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd[2];
int ret = socketpair(AF_UNIX, SOCK_STREAM, 0,fd);
if(ret != 0){
perror("socketpair");
return -1;
}
pid_t pid = fork();
if(pid == 0){ // Child process
close(fd[1]);
int val = 0;
while(1){
sleep(1);
++val;
write(fd[0], &val, sizeof(val));
read(fd[0], &val, sizeof(val));
printf("Child : %d\n", val);
}
}else{ // Parent process
close(fd[0]);
int val;
while(1){
read(fd[1], &val, sizeof(val));
printf("Parent : %d\n", val);
++val;
write(fd[1], &val, sizeof(val));
}
}
return 0;
}