linux进程通信方式及其详细实例

概述

进程通信是现代操作系统中非常重要的概念之一,它使得不同进程之间能够协同工作,实现更加复杂的应用程序。进程通信可以通过多种方式实现,其中一些常见的方式包括管道、消息队列、共享内存和信号量等。

进程通信方式

在Linux系统中,进程通信的方式有多种,以下是其中几种常见的方式:

管道(Pipe):是一种半双工的通信方式,它只能用于具有亲缘关系的进程间的通信。一个进程将数据写入管道,而另一个进程则从管道中读取数据。

命名管道(Named Pipe):也是一种半双工的通信方式,不同之处在于,它可以用于任意进程之间的通信。

信号(Signal):是一种比较简单的通信方式,用于通知接收进程某个事件已经发生。信号可以由内核、进程或者用户发送。

共享内存(Shared Memory):是一种高效的通信方式,它允许多个进程共享同一块物理内存区域。多个进程可以在该内存区域中读写数据,从而实现进程间的通信。

信号量(Semaphore):是一种用于进程同步的机制,可以用于控制多个进程对共享资源的访问。信号量可以用来实现进程间的互斥和同步。

消息队列(Message Queue):是一种基于消息的通信方式,进程可以向消息队列发送消息,并从队列中读取消息。消息队列可以用于不同进程之间的通信。

套接字(Socket):是一种通用的进程通信方式,可以用于不同机器之间的进程通信,也可以用于同一机器上的进程通信。套接字可以支持不同的网络协议,例如TCP/IP和UDP。

管道(Pipe)

管道是一种半双工的通信方式,只能用于具有亲缘关系的进程间的通信。一个进程将数据写入管道,另一个进程则从管道中读取数据。管道有两种类型,分别为无名管道和命名管道。

无名管道的创建需要调用pipe函数,函数原型为:

int pipe(int pipefd[2]);
其中pipefd[0]和pipefd[1]是两个文件描述符,分别用于读和写管道。下面是一个简单的示例,创建一个无名管道并在父进程和子进程之间进行通信:

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

int main() {
    int fd[2], pid;
    char buf[20];

    if (pipe(fd) == -1) {  // 创建管道
        perror("pipe");
        exit(1);
    }

    if ((pid = fork()) == -1) {  // 创建子进程
        perror("fork");
        exit(1);
    }

    if (pid == 0) {  // 子进程写入管道
        close(fd[0]);  // 关闭读端
        write(fd[1], "Hello, parent", 14);
        close(fd[1]);
    } else {  // 父进程读取管道
        close(fd[1]);  // 关闭写端
        read(fd[0], buf, 20);
        printf("Received message: %s\n", buf);
        close(fd[0]);
    }

    return 0;
}

命名管道也叫FIFO,它是一种特殊的文件类型,可以用于任意进程之间的通信。命名管道的创建需要调用mkfifo函数,函数原型为:

int mkfifo(const char *pathname, mode_t mode);

其中pathname是管道文件的路径名,mode是文件权限。下面是一个简单的示例,创建一个命名管道并在父进程和子进程之间进行通信:

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

#define FIFO_PATH "/tmp/myfifo"

int main() {
    int fd, pid;
    char buf[20];

    if (mkfifo(FIFO_PATH, 0666) == -1) {  // 创建命名管道
        perror("mkfifo");
        exit(1);
    }

    if ((pid = fork()) == -1) {  // 创建子进程
        perror("fork");
        exit(1);
    }

    if (pid == 0) {  // 子进程写入管道
        fd = open(FIFO_PATH, O_WRONLY);
        write(fd, "Hello, parent", 14);
close(fd);
} else { // 父进程读取管道
fd = open(FIFO_PATH, O_RDONLY);
read(fd, buf, 20);
printf("Received message: %s\n", buf);
close(fd);
}

return 0;
}

消息队列

消息队列是一种进程间通信的方式,允许一个进程向另一个进程发送消息。它是一种异步通信方式,发送方发送消息后即可继续执行,不必等待接收方的响应。

在C语言中,可以通过消息队列函数来创建消息队列,具体代码如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define MSGSIZE 16

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

int main()
{
    int msqid;
    key_t key;
    struct msgbuf buf;

    if ((key = ftok(".", 'a')) == -1) {
        perror("ftok");
        exit(1);
    }

    if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) {
        perror("msgget");
        exit(1);
    }

    buf.mtype = 1;
    sprintf(buf.mtext, "Hello, world!");
    if (msgsnd(msqid, &buf, MSGSIZE, 0) == -1) {
        perror("msgsnd");

if (msgrcv(msqid, &buf, MSGSIZE, 1, 0) == -1) {
    perror("msgrcv");
    exit(1);
}

printf("接收到的消息:%s\n", buf.mtext);

if (msgctl(msqid, IPC_RMID, NULL) == -1) {
    perror("msgctl");
    exit(1);
}

return 0;
}

这段代码中,通过ftok函数创建一个唯一的key,然后通过msgget函数创建一个消息队列。发送方向消息队列中发送了一条消息,接收方从消息队列中读取并输出该消息。最后通过msgctl函数删除消息队列。

共享内存(Shared Memory)

共享内存是一种高效的IPC机制,它允许多个进程共享同一个物理内存区域,从而避免了数据拷贝和进程切换的开销。共享内存的创建需要调用shmget函数和shmat函数,函数原型如下:

int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);

其中key是共享内存的键值,size是共享内存的大小,shmflg是标志位。下面是一个简单的示例,创建一个共享内存区域并在父进程和子进程之间进行通信:


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>

#define SHM_KEY 1234

struct shared_memory {
    int count;
    char data[20];
};

int main() {
    int shmid, pid;
    struct shared_memory *shm;

    shmid = shmget(SHM_KEY, sizeof(struct shared_memory), 0666 | IPC_CREAT);  // 创建共享内存
    if (shmid == -1) {
        perror("shmget");
        exit(1);
    }

    shm = shmat(shmid, NULL, 0);  // 将共享内存映射到进程的地址空间
    if (shm == (void *)-1) {
        perror("shmat");
        exit(1);
    }

    shm->count = 0;  // 初始化共享内存中的数据

    if ((pid = fork()) == -1) {  // 创建子进程
        perror("fork");
        exit(1);
    }

    if (pid == 0) {  // 子进程访问共享内存
        while (1) {
            shm->count++;
            sprintf(shm->data, "Count: %d", shm->count);
			sleep(1);
}
} else { // 父进程访问共享内存
while (1) {
printf("%s\n", shm->data);
sleep(1);
}
}

return 0;
}

套接字通信(Socket Communication)

套接字通信是指使用套接字进行进程间通信的方式。套接字通信可以在不同主机之间进行,同时也可以使用不同的网络协议进行通信。套接字通信一般包括创建套接字、连接套接字、发送数据和接收数据等步骤。以下是一个使用套接字进行进程通信的c语言示例:

信号(Signal)

信号是一种异步通信方式,当进程接收到一个信号时,会打断当前的执行,转而执行与该信号相关联的信号处理函数。Linux提供了许多信号,如SIGINT、SIGTERM、SIGKILL等。可以使用signal函数或sigaction函数来注册信号处理函数,下面是一个简单的示例:

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

void handler(int sig) {
    printf("Received signal %d\n", sig);
}

int main() {
    signal(SIGINT, handler);  // 注册信号处理函数
    while (1) {
        printf("Running...\n");
        sleep(1);
    }
    return 0;
}

该程序会不断输出"Running…“,当用户按下CTRL+C时,会打印出"Received signal 2”,然后继续运行。

信号量(Semaphore)

信号量是一种计数器,用于控制对共享资源的访问。每次进程访问共享资源时,都要先获取一个信号量,如果信号量的值大于0,则进程可以继续访问,否则进程需要等待。访问完成后,进程会释放信号量,使其值加1,以便其他进程访问。Linux提供了semget函数、semop函数和semctl函数来创建和操作信号量,下面是一个简单的示例:链接

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值