进程间通信(IPC,Inter-Process Communication)是指在不同进程之间传递数据或信号的机制。由于进程之间的地址空间是独立的,IPC提供了一种在进程之间进行数据交换的方法。以下是几种常见的IPC机制:
1. 管道(Pipes)
匿名管道
匿名管道是单向的通信通道,通常用于具有亲缘关系的进程之间(如父子进程)。
#include <stdio.h>
#include <unistd.h>
int main() {
int fd[2];
pipe(fd);
if (fork() == 0) {
// 子进程
close(fd[0]); // 关闭读端
write(fd[1], "Hello, parent!", 15);
close(fd[1]);
} else {
// 父进程
char buffer[15];
close(fd[1]); // 关闭写端
read(fd[0], buffer, 15);
printf("Received from child: %s\n", buffer);
close(fd[0]);
}
return 0;
}
命名管道(FIFO)
命名管道可以在不相关的进程之间进行通信。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
const char *fifo = "/tmp/my_fifo";
mkfifo(fifo, 0666);
if (fork() == 0) {
// 子进程
int fd = open(fifo, O_WRONLY);
write(fd, "Hello, parent!", 15);
close(fd);
} else {
// 父进程
char buffer[15];
int fd = open(fifo, O_RDONLY);
read(fd, buffer, 15);
printf("Received from child: %s\n", buffer);
close(fd);
unlink(fifo);
}
return 0;
}
2. 消息队列(Message Queues)
消息队列允许进程以消息的形式进行通信,消息可以按照优先级进行排序。
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msg_buffer {
long msg_type;
char msg_text[100];
};
int main() {
key_t key = ftok("progfile", 65);
int msgid = msgget(key, 0666 | IPC_CREAT);
if (fork() == 0) {
// 子进程
struct msg_buffer message;
message.msg_type = 1;
sprintf(message.msg_text, "Hello, parent!");
msgsnd(msgid, &message, sizeof(message), 0);
} else {
// 父进程
struct msg_buffer message;
msgrcv(msgid, &message, sizeof(message), 1, 0);
printf("Received from child: %s\n", message.msg_text);
msgctl(msgid, IPC_RMID, NULL);
}
return 0;
}
3. 共享内存(Shared Memory)
共享内存允许多个进程共享一块内存区域,是最快的IPC机制之一。
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main() {
key_t key = ftok("shmfile", 65);
int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
char *str = (char*) shmat(shmid, (void*)0, 0);
if (fork() == 0) {
// 子进程
sprintf(str, "Hello, parent!");
shmdt(str);
} else {
// 父进程
sleep(1); // 确保子进程先写入
printf("Received from child: %s\n", str);
shmdt(str);
shmctl(shmid, IPC_RMID, NULL);
}
return 0;
}
4. 信号(Signals)
信号是一种用于通知进程某个事件发生的机制。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void signal_handler(int signum) {
printf("Received signal %d\n", signum);
}
int main() {
signal(SIGUSR1, signal_handler);
if (fork() == 0) {
// 子进程
sleep(1); // 确保父进程先设置信号处理函数
kill(getppid(), SIGUSR1);
} else {
// 父进程
pause(); // 等待信号
}
return 0;
}
5. 套接字(Sockets)
套接字不仅可以用于同一台机器上的进程间通信,还可以用于不同机器之间的通信。
// 服务器端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[1024] = {0};
server_fd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
bind(server_fd, (struct sockaddr *)&address, sizeof(address));
listen(server_fd, 3);
new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
read(new_socket, buffer, 1024);
printf("Received from client: %s\n", buffer);
close(new_socket);
close(server_fd);
return 0;
}
// 客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char *message = "Hello, server!";
sock = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
send(sock, message, strlen(message), 0);
close(sock);
return 0;
}
总结
不同的IPC机制有不同的适用场景和优缺点:
- 管道:适用于简单的父子进程通信。
- 消息队列:适用于需要消息排序和优先级的场景。
- 共享内存:适用于需要高效大数据量传输的场景。
- 信号:适用于简单的事件通知。
- 套接字:适用于网络通信和不同机器之间的通信。
选择合适的IPC机制可以提高程序的效率和可靠性。
标签:IPC,int,间通信,buffer,详解,fd,进程,message,include From: https://blog.csdn.net/weixin_53442127/article/details/142316804