Linux进程间通信的方式

目录

管道(pipe)

消息队列(message queue)

共享内存(shared memory)

信号(signal)

套接字(socket)

在Linux系统中,进程是相互独立运行的,但是有时候需要不同进程之间进行通信,以实现数据共享和协作。Linux系统提供了多种进程间通信的方式,本文将详细介绍这些方式,并配以实例。

  1. 管道(pipe)

管道是一种最简单的进程间通信方式,它可以在一个进程中创建一个管道,然后将数据写入管道,另一个进程从管道中读取数据。管道分为有名管道和无名管道,无名管道只能在父子进程之间使用,而有名管道可以在不同进程之间使用。

重点:管道是最简单的进程间通信方式,可以在一个进程中创建一个管道,然后将数据写入管道,另一个进程从管道中读取数据。

注意事项:无名管道只能在父子进程之间使用,而有名管道可以在不同进程之间使用。同时管道的缓冲区大小有限,如果写入数据超过缓冲区大小,就会阻塞写入进程。

实例:

创建无名管道,父进程向子进程传递数据

#include 
#include 
#include 

int main()
{
    int fd[2];
    pid_t pid;
    char buf[1024];

    if (pipe(fd) < 0) {
        perror("pipe error");
        exit(1);
    }

    if ((pid = fork()) < 0) {
        perror("fork error");
        exit(1);
    } else if (pid > 0) {
        close(fd[0]);
        write(fd[1], "hello world\n", 12);
    } else {
        close(fd[1]);
        read(fd[0], buf, 1024);
        printf("%s", buf);
    }
    return 0;
}
  1. 消息队列(message queue)

消息队列是一种进程间通信的方式,它可以在不同进程之间传递数据,每个消息都有一个类型和一个数据,接收方可以按照类型接收数据。消息队列可以实现异步通信,发送方可以继续执行其他任务,而不必等待接收方接收数据。

重点:消息队列可以在不同进程之间传递数据,每个消息都有一个类型和一个数据,接收方可以按照类型接收数据。消息队列可以实现异步通信,发送方可以继续执行其他任务,而不必等待接收方接收数据。

注意事项:消息队列需要创建和删除,需要注意权限和安全问题。同时消息队列的大小有限,如果写入数据超过队列大小,就会出现消息丢失的情况。

实例:

创建消息队列,父进程向子进程发送消息

#include 
#include 
#include 
#include 
#include 

struct msgbuf {
    long mtype;
    char mtext[1024];
};

int main()
{
    int msgid;
    pid_t pid;
    struct msgbuf buf;

    if ((msgid = msgget(IPC_PRIVATE, 0644)) == -1) {
        perror("msgget error");
        exit(1);
    }

    if ((pid = fork()) < 0) {
        perror("fork error");
        exit(1);
    } else if (pid > 0) {
        buf.mtype = 1;
        sprintf(buf.mtext, "hello world");
        msgsnd(msgid, &buf, sizeof(buf.mtext), 0);
    } else {
        msgrcv(msgid, &buf, sizeof(buf.mtext), 1, 0);
        printf("%s\n", buf.mtext);
        msgctl(msgid, IPC_RMID, NULL);
    }
    return 0;
}
  1. 共享内存(shared memory)

共享内存是一种高效的进程间通信方式,它可以在不同进程之间共享同一块内存区域,从而实现数据共享。共享内存可以提高程序的执行效率,但是需要注意同步问题,以避免数据竞争。

重点:共享内存是一种高效的进程间通信方式,可以在不同进程之间共享同一块内存区域,从而实现数据共享。共享内存可以提高程序的执行效率,但是需要注意同步问题,以避免数据竞争。

注意事项:共享内存需要创建和删除,需要注意权限和安全问题。同时共享内存的大小有限,如果写入数据超过内存大小,就会出现数据覆盖的情况。

实例:

创建共享内存,父进程和子进程共享内存区域

#include 
#include 
#include 
#include 

int main()
{
    int shmid;
    pid_t pid;
    char *ptr;

    if ((shmid = shmget(IPC_PRIVATE, 1024, 0644)) == -1) {
        perror("shmget error");
        exit(1);
    }

    if ((pid = fork()) < 0) {
        perror("fork error");
        exit(1);
    } else if (pid > 0) {
        ptr = shmat(shmid, NULL, 0);
        sprintf(ptr, "hello world");
        shmdt(ptr);
    } else {
        ptr = shmat(shmid, NULL, 0);
        printf("%s\n", ptr);
        shmdt(ptr);
        shmctl(shmid, IPC_RMID, NULL);
    }
    return 0;
}
  1. 信号(signal)

信号是一种异步的进程间通信方式,它可以在不同进程之间传递信息,比如通知进程某个事件发生或者中断进程执行。信号可以实现简单的进程间通信,但是需要注意信号处理函数的编写,以保证程序的正确性。

重点:信号是一种异步的进程间通信方式,可以在不同进程之间传递信息,比如通知进程某个事件发生或者中断进程执行。信号可以实现简单的进程间通信,但是需要注意信号处理函数的编写,以保证程序的正确性。

注意事项:信号处理函数需要注意并发和同步问题,以保证程序的正确性。同时信号处理函数需要尽可能的简单,避免出现复杂的业务逻辑。

实例:

父进程向子进程发送SIGUSR1信号

#include 
#include 
#include 
#include 

void sig_handler(int signo)
{
    if (signo == SIGUSR1) {
        printf("received SIGUSR1\n");
    }
}

int main()
{
    pid_t pid;

    if ((pid = fork()) < 0) {
        perror("fork error");
        exit(1);
    } else if (pid > 0) {
        sleep(1);
        kill(pid, SIGUSR1);
    } else {
        signal(SIGUSR1, sig_handler);
        while (1) {
            sleep(1);
        }
    }
    return 0;
}
  1. 套接字(socket)

套接字是一种进程间通信的方式,它可以在不同进程之间传递数据,比如网络通信和本地通信。套接字可以实现复杂的进程间通信,但是需要注意网络安全和性能问题。

重点:套接字是一种进程间通信的方式,可以在不同进程之间传递数据,比如网络通信和本地通信。套接字可以实现复杂的进程间通信,但是需要注意网络安全和性能问题。

注意事项:套接字需要创建和删除,需要注意权限和安全问题。同时套接字的传输速度受到网络带宽和延迟的影响,需要注意传输效率。

实例:

创建本地套接字,父进程向子进程发送数据

#include 
#include 
#include 
#include 
#include 

int main()
{
    int sockfd;
    pid_t pid;
    char buf[1024];
    struct sockaddr_un addr;

    if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket error");
        exit(1);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, "/tmp/test.sock");

    if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("bind error");
        exit(1);
    }

    if (listen(sockfd, 5) == -1) {
        perror("listen error");
        exit(1);
    }

    if ((pid = fork()) < 0) {
        perror("fork error");
        exit(1);
    } else if (pid > 0) {
        close(sockfd);
        sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
        connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
        write(sockfd, "hello world", 12);
    } else {
        int connfd = accept(sockfd, NULL, NULL);
        read(connfd, buf, 1024);
        printf("%s\n", buf);
    }
    return 0;
}

总结:

Linux系统提供了多种进程间通信的方式,每种方式都有自己的特点和适用场景。在实际开发中,需要根据具体情况选择合适的进程间通信方式,以保证程序的正确性和高效性。

你可能感兴趣的:(linux,linux,服务器,网络,c语言)