Linux进程间通信
本帖最后由 0xlavon 于 2024-5-22 12:52 编辑在Linux操作系统中,进程间通信(Inter-Process Communication, IPC)是进程之间传递数据或信号的机制。IPC在多进程编程中至关重要,适用于资源共享、数据同步、事件通知等场景。本文将介绍几种常见的Linux进程间通信方式,并给出相应的代码示例。
1. 管道(Pipes)
管道是一种最简单的进程间通信方式,主要用于父子进程之间的数据传输。
1.1 匿名管道(Unnamed Pipes)
匿名管道只能用于具有亲缘关系的进程之间,即父进程与子进程之间。
1.1.1 创建与使用
匿名管道通过`pipe()`系统调用创建:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int pipefd;
char buffer;
pid_t cpid;
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* 子进程 */
close(pipefd); /* 关闭写端 */
read(pipefd, buffer, sizeof(buffer));
printf("子进程接收到的数据: %s\n", buffer);
close(pipefd);
} else { /* 父进程 */
close(pipefd); /* 关闭读端 */
write(pipefd, "Hello, child process", 21);
close(pipefd);
}
return 0;
}
1.2 命名管道(Named Pipes, FIFO)
命名管道可以用于任何两个进程之间的通信,具有路径名,与文件类似。
1.2.1 创建与使用
使用`mkfifo()`创建命名管道:
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
char *fifo = "/tmp/my_fifo";
char buffer;
if (mkfifo(fifo, 0666) == -1) {
perror("mkfifo");
exit(EXIT_FAILURE);
}
pid_t cpid = fork();
if (cpid == 0) { /* 子进程 */
int fd = open(fifo, O_RDONLY);
read(fd, buffer, sizeof(buffer));
printf("子进程接收到的数据: %s\n", buffer);
close(fd);
} else { /* 父进程 */
int fd = open(fifo, O_WRONLY);
write(fd, "Hello, child process", 21);
close(fd);
}
return 0;
}
2. 消息队列(Message Queues)
消息队列允许进程以消息的形式进行通信,支持异步操作,且能够实现数据的结构化传输。
2.1 创建与使用
消息队列通过`msgget()`、`msgsnd()`、`msgrcv()`等系统调用进行操作:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct msg_buffer {
long msg_type;
char msg_text;
};
int main() {
key_t key;
int msgid;
struct msg_buffer message;
key = ftok("progfile", 65);
msgid = msgget(key, 0666 | IPC_CREAT);
message.msg_type = 1;
strcpy(message.msg_text, "Hello, message queue");
msgsnd(msgid, &message, sizeof(message), 0);
msgrcv(msgid, &message, sizeof(message), 1, 0);
printf("接收到的消息: %s\n", message.msg_text);
msgctl(msgid, IPC_RMID, NULL);
return 0;
}
3. 共享内存(Shared Memory)
共享内存是最快的IPC方式,允许多个进程直接访问同一块内存区域。
3.1 创建与使用
共享内存通过`shmget()`、`shmat()`、`shmdt()`等系统调用进行操作:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.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);
strcpy(str, "Hello, shared memory");
printf("写入数据: %s\n", str);
shmdt(str);
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
4. 信号量(Semaphores)
信号量主要用于进程同步,但也可以用于进程间通信。
4.1 创建与使用
信号量通过`semget()`、`semop()`、`semctl()`等系统调用进行操作:
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
union semun {
int val;
struct semid_ds *buf;
unsigned short*array;
};
int main() {
key_t key = ftok("semfile", 65);
int semid = semget(key, 1, 0666 | IPC_CREAT);
union semun u;
u.val = 1;
semctl(semid, 0, SETVAL, u);
struct sembuf sb = {0, -1, 0};// P操作
semop(semid, &sb, 1);
printf("进入临界区\n");
sleep(2);// 模拟临界区操作
printf("退出临界区\n");
sb.sem_op = 1;// V操作
semop(semid, &sb, 1);
semctl(semid, 0, IPC_RMID);
return 0;
}
5. 套接字(Sockets)
套接字不仅用于网络通信,也可以用于本地进程间通信(Unix Domain Sockets)。
5.1 创建与使用
本地套接字通过`socket()`、`bind()`、`listen()`、`accept()`等系统调用进行操作:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define SOCKET_PATH "/tmp/socket"
int main() {
int server_fd, client_fd;
struct sockaddr_un addr;
char buffer;
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
bind(server_fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un));
listen(server_fd, 5);
client_fd = accept(server_fd, NULL, NULL);
read(client_fd, buffer, sizeof(buffer));
printf("接收到的数据: %s\n", buffer);
close(client_fd);
close(server_fd);
unlink(SOCKET_PATH);
return 0;
}
6. 总结
Linux提供了多种进程间通信方式,每种方式都有其适用的场景和优缺点:
(1) 管道(匿名管道和命名管道)简单易用,适用于父子进程或相关进程之间的通信。
(2) 消息队列适用于需要结构化数据传输且通信双方相对独立的场景。
(3) 共享内存是最快的通信方式,但需要进程间同步机制确保数据一致性。
(4) 信号量主要用于进程同步,也可以结合其他IPC方式使用。
(5) 套接字适用于本地和网络通信,具有很强的灵活性和扩展性。
选择合适的IPC方式,能够有效提高系统的性能和稳定性。希望本文能帮助读者更好地理解和应用Linux进程间通信技术。Happy coding with Linux IPC!
页:
[1]