在复杂的软件系统中,脚本进程之间的高效交流与协作是保证系统稳定性和功能完善性的关键。以下是几种实用且高效的通信技巧,帮助你在脚本进程间轻松实现跨进程沟通。
1. 使用管道(Pipes)
管道是Linux和Unix系统中常用的进程间通信(IPC)方法。通过管道,一个进程可以将数据传递给另一个进程。管道分为无名管道和命名管道两种。
- 无名管道:适用于父子进程或兄弟进程之间的通信,使用
pipe()系统调用创建。 - 命名管道:也称为FIFO,允许不同进程在不同目录下通信,通过文件系统中的命名管道实现。
#include <unistd.h>
#include <stdio.h>
int main() {
int pipe_fd[2];
if (pipe(pipe_fd) == -1) {
perror("pipe");
return 1;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return 1;
}
if (pid == 0) { // 子进程
close(pipe_fd[0]); // 关闭读端
dup2(pipe_fd[1], STDOUT_FILENO); // 将输出重定向到管道
execlp("echo", "echo", "Hello from child", (char *)NULL);
perror("execlp");
close(pipe_fd[1]);
} else { // 父进程
close(pipe_fd[1]); // 关闭写端
dup2(pipe_fd[0], STDIN_FILENO); // 将输入重定向到管道
char buffer[100];
read(pipe_fd[0], buffer, sizeof(buffer));
printf("Parent received: %s\n", buffer);
close(pipe_fd[0]);
}
return 0;
}
2. 消息队列(Message Queues)
消息队列是一种存储消息的先进先出(FIFO)的数据结构,允许进程发送和接收消息。它适用于消息传递,其中消息可以是任何类型的数据。
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#define QUEUE_KEY 1234
typedef struct {
long msg_type;
char msg_text[100];
} msg_queue;
int main() {
key_t key = ftok("queue_file", QUEUE_KEY);
if (key == -1) {
perror("ftok");
return 1;
}
int msg_id = msgget(key, 0666 | IPC_CREAT);
if (msg_id == -1) {
perror("msgget");
return 1;
}
// 发送消息
msg_queue msg = {1, "Hello from sender"};
if (msgsend(msg_id, &msg, sizeof(msg), 0) == -1) {
perror("msgsend");
return 1;
}
// 接收消息
msg_queue received_msg;
if (msgrcv(msg_id, &received_msg, sizeof(received_msg), 1, 0) == -1) {
perror("msgrcv");
return 1;
}
printf("Received message: %s\n", received_msg.msg_text);
// 清理
msgctl(msg_id, IPC_RMID, NULL);
return 0;
}
3. 信号量(Semaphores)
信号量是一种用于多进程同步的机制,它可以是二进制信号量或计数信号量。信号量可以用来保护共享资源,避免竞态条件。
#include <semaphore.h>
#include <pthread.h>
#include <stdio.h>
sem_t semaphore;
void *thread_function(void *arg) {
sem_wait(&semaphore); // 获取信号量
// 访问共享资源
printf("Thread %ld is accessing the resource.\n", (long)arg);
sleep(1);
sem_post(&semaphore); // 释放信号量
return NULL;
}
int main() {
pthread_t threads[10];
// 初始化信号量
sem_init(&semaphore, 0, 1);
for (long i = 0; i < 10; ++i) {
if (pthread_create(&threads[i], NULL, thread_function, (void *)i) != 0) {
perror("pthread_create");
return 1;
}
}
for (long i = 0; i < 10; ++i) {
pthread_join(threads[i], NULL);
}
// 清理信号量
sem_destroy(&semaphore);
return 0;
}
4. 共享内存(Shared Memory)
共享内存允许多个进程访问同一块内存区域,从而实现高效的数据共享。
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#define SHARED_MEMORY_KEY 5678
#define SHARED_MEMORY_SIZE 1024
int main() {
int shm_id = shmget(SHARED_MEMORY_KEY, SHARED_MEMORY_SIZE, 0666 | IPC_CREAT);
if (shm_id == -1) {
perror("shmget");
return 1;
}
char *shared_memory = shmat(shm_id, NULL, 0);
if (shared_memory == (char *)(-1)) {
perror("shmat");
return 1;
}
// 读写共享内存
strcpy(shared_memory, "Hello from shared memory");
printf("Read from shared memory: %s\n", shared_memory);
// 清理
shmdt(shared_memory);
shmctl(shm_id, IPC_RMID, NULL);
return 0;
}
5. Sockets
套接字是一种网络通信的机制,它可以用于同一台计算机上的进程间通信,也可以用于不同计算机之间的通信。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 创建 socket 文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 强制绑定到端口
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
// 绑定 socket 到端口 8080
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 发送数据
const char *hello = "Hello from server";
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
// 关闭连接
close(new_socket);
close(server_fd);
return 0;
}
通过上述几种方法,你可以根据具体的需求和场景选择合适的通信方式,实现脚本进程间的高效交流与协作。
