在Linux系统中,进程间通信(Inter-Process Communication, IPC)是一个非常重要的主题,尤其是在多任务操作系统中,不同的进程需要一种可靠的方式来进行数据交换和协同工作。Socket作为一种通用的通信机制,在Linux下被广泛应用于网络编程以及本地进程间的通信。
1. 基于Unix Domain Socket的IPC
Unix Domain Socket是一种特殊的socket类型,它允许在同一台机器上的不同进程之间进行高效的数据传输。与TCP/IP协议族中的套接字不同,Unix Domain Socket并不依赖于网络协议栈,而是通过文件系统路径来建立连接。这种方式不仅减少了网络延迟,还提供了更高的安全性和性能。
创建一个Unix Domain Socket服务器端可以这样实现:
```c
include
include
include
int main() {
int sockfd;
struct sockaddr_un addr;
// 创建socket
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/uds_socket");
// 绑定地址
if (bind(sockfd, (struct sockaddr)&addr, sizeof(addr)) == -1) {
perror("bind");
close(sockfd);
exit(EXIT_FAILURE);
}
listen(sockfd, 5);
while (1) {
int client_sockfd;
client_sockfd = accept(sockfd, NULL, NULL);
if (client_sockfd == -1) {
perror("accept");
continue;
}
write(client_sockfd, "Hello Client", 12);
close(client_sockfd);
}
}
```
客户端则可以通过以下代码连接到这个服务:
```c
int main() {
int sockfd;
struct sockaddr_un addr;
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/uds_socket");
if (connect(sockfd, (struct sockaddr)&addr, sizeof(addr)) == -1) {
perror("connect");
close(sockfd);
exit(EXIT_FAILURE);
}
char buf[128];
read(sockfd, buf, sizeof(buf));
printf("Received: %s\n", buf);
close(sockfd);
return 0;
}
```
2. 使用管道(pipe)进行IPC
管道是一种简单的IPC方式,主要用于父子进程或兄弟进程之间的通信。它基于文件描述符操作,提供了一种半双工的通信模式。Linux支持两种类型的管道:匿名管道和命名管道(FIFO)。
匿名管道通常用于父子进程间通信,而命名管道则可以在不相关的进程之间使用。下面展示如何使用匿名管道实现简单的通信:
```c
include
include
include
int main() {
int pipefd[2];
pid_t pid;
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) { // 子进程
close(pipefd[1]); // 关闭写端
char buffer[128];
read(pipefd[0], buffer, sizeof(buffer));
printf("Child received: %s\n", buffer);
close(pipefd[0]);
exit(EXIT_SUCCESS);
} else { // 父进程
close(pipefd[0]); // 关闭读端
write(pipefd[1], "Hello from parent", 16);
close(pipefd[1]);
wait(NULL); // 等待子进程结束
exit(EXIT_SUCCESS);
}
}
```
3. 消息队列(Message Queue)
消息队列是另一种常用的IPC机制,允许消息以先进先出(FIFO)的形式存储,并且可以设置优先级。每个消息都有一个特定的类型,这使得它可以被指定的接收者处理。
为了使用消息队列,我们需要包含头文件`
```c
include
include
include
include
struct msg_buffer {
long msg_type;
char msg_text[100];
} message;
int main() {
key_t key;
int msgid;
key = ftok("progfile", 65);
if ((msgid = msgget(key, 0666 | IPC_CREAT)) == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
message.msg_type = 1;
strcpy(message.msg_text, "Hello, world!");
if (msgsnd(msgid, &message, sizeof(message.msg_text), 0) == -1) {
perror("msgsnd");
exit(EXIT_FAILURE);
}
printf("Message sent\n");
exit(EXIT_SUCCESS);
}
```
以上介绍了三种常见的Linux进程间通信方法。每种方法都有其适用场景和优缺点,选择合适的IPC方式对于构建高效的分布式系统至关重要。