返回

Linux 套接字和信号:进程间通信的终极指南

见解分享

进程间通信(IPC)的利器:套接字和信号

在本文中,我们将深入探讨 Linux 下进程间通信 (IPC) 的两个强大机制:套接字和信号。通过它们,你可以实现进程之间的顺畅交流,即使它们在同一台机器上或分布在不同的机器上。

套接字:跨越机器的桥梁

套接字是一个双向通信通道,允许进程通过网络进行通信。它们是跨机器和平台进行 IPC 的基石。套接字编程接口(API)提供了一组函数,可以创建、绑定、监听和连接套接字。

套接字有两种主要类型:

  • 流式套接字: 提供面向连接的可靠通信,就像一条管道,数据可以顺序流过。
  • 数据报套接字: 提供无连接的、不可靠的通信,就像一封信,数据作为一个单元发送,可能会丢失或乱序。

信号:进程间快速通知

信号是内核用来通知进程特定事件的机制。它们是一种轻量级的 IPC 机制,用于发送异步通知,例如:

  • 键盘中断(Ctrl+C)
  • 进程终止
  • 子进程完成

进程可以通过调用 signal() 函数来注册信号处理程序,当收到特定信号时,该处理程序将执行。

套接字编程实战

让我们使用示例代码来演示如何使用套接字进行 IPC。以下示例创建一个简单的服务器,监听来自客户端的连接,然后发送一条消息:

#include <sys/socket.h>
#include <netinet/in.h>

int main() {
  int server_sockfd;
  struct sockaddr_in server_addr;

  // 创建一个套接字
  server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

  // 初始化服务器地址结构
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = INADDR_ANY;
  server_addr.sin_port = htons(8080);

  // 绑定套接字到地址
  bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

  // 监听连接
  listen(server_sockfd, 5);

  // 接受连接
  struct sockaddr_in client_addr;
  socklen_t client_addr_len = sizeof(client_addr);
  int client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &client_addr_len);

  // 发送消息
  const char *message = "Hello from server!";
  send(client_sockfd, message, strlen(message), 0);

  // 关闭套接字
  close(server_sockfd);
  close(client_sockfd);

  return 0;
}

客户端代码如下:

#include <sys/socket.h>
#include <netinet/in.h>

int main() {
  int client_sockfd;
  struct sockaddr_in server_addr;

  // 创建一个套接字
  client_sockfd = socket(AF_INET, SOCK_STREAM, 0);

  // 初始化服务器地址结构
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  server_addr.sin_port = htons(8080);

  // 连接到服务器
  connect(client_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

  // 接收消息
  char buffer[1024];
  recv(client_sockfd, buffer, sizeof(buffer), 0);

  // 打印消息
  printf("Received: %s\n", buffer);

  // 关闭套接字
  close(client_sockfd);

  return 0;
}

信号处理实例

现在,我们使用一个例子来了解信号处理。以下代码创建一个子进程,并在父进程中注册一个信号处理程序,当子进程完成时处理程序将执行:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void child_handler(int signum) {
  // 信号处理程序
  printf("Child process completed!\n");
}

int main() {
  pid_t child_pid;

  // 注册信号处理程序
  signal(SIGCHLD, child_handler);

  // 创建子进程
  child_pid = fork();

  if (child_pid == 0) {
    // 子进程
    sleep(5);
    exit(0);
  } else {
    // 父进程
    while (1) {
      // 等待子进程完成
      sleep(1);
    }
  }

  return 0;
}

总结

套接字和信号是 Linux 下 IPC 的强大工具。套接字允许进程在机器内和机器间进行通信,而信号提供了一种快速通知进程的方式。通过本文的介绍,你现在已经掌握了使用这些机制在应用程序中实现进程间通信所需的知识。