Linux 进程通信

本文详细介绍了Linux下进程通信的八种方法:管道、命名管道、共享内存、消息队列、信号量、信号、套接字及后台执行的概念,并提供了管道和命名管道的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux下进程通信的八种方法:管道(pipe),命名管道(FIFO),共享内存(shared memory),消息队列(message queue),信号量(semaphore),信号(signal),套接字(Socket)

linux命令中,执行一个程序,后面加上&,代表后台执行,也就是执行这个程序的同时,你的终端同时还会做其他的事情,如果不加这个符号,那么你执行这个程序后,你的终端只能等这个程序执行完成后才能够继续执行其他操作。


    (1) 管道(pipe):管道允许一个进程和另一个与它有共同祖先的进程之间进行通信;

 举例:

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

static int fd1[2],fd2[2];

void TELL_WAIT(){
     pipe(fd1);
     pipe(fd2);
}

void TELL_PARENT(pid_t pid){
     write(fd2[1],"c",1);
}

void WAIT_PARENT(void){
     char c;
     read(fd1[0],&c,1);
     if(c != 'p'){
          printf("WAIT_PARENT: Incorretc data"); 
          exit(0);
     }
     else{
          printf("read from parent\n");
     }      
}

void TELL_CHILD(pid_t pid){
     write(fd1[1],"p",1);
}

void WAIT_CHILD(){
     char c;
     read(fd2[0],&c,1);
     if(c != 'c'){
          printf("WAIT_PARENT: Incorrect data");
          exit(0);
     }else{
          printf("Read from child.\n");
     }
}

int main(){
    pid_t pid;
    TELL_WAIT();
    pid = fork();
    if(pid == -1){
          perror("fork() error");
          exit(-1);
    }
    if(pid == 0){
         printf("child process exec.\n");
         WAIT_PARENT();
         TELL_PARENT(getppid());  
    }
    else{
         printf("parent process exec.\n");
         TELL_CHILD(pid);
         WAIT_CHILD();
    }
    exit(0);
}



    (2) 命名管道(FIFO):类似于管道,但是它可以用于任何两个进程之间的通信,命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建;

  有亲缘关系:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

#define FIFO1   "/tmp/fifo.1"
#define FIFO2   "/tmp/fifo.2"

int main()
{
    int readfd,writefd;
    pid_t   childpid;
    char buf[100];
    memset(buf,0,100);
    //创建FIFO
    if((mkfifo(FIFO1,FILE_MODE) < 0) && (errno != EEXIST))
    {
        perror("mkfifo() error");
        exit(-1);
    }
    if((mkfifo(FIFO2,FILE_MODE) < 0) && (errno != EEXIST))
    {
        unlink(FIFO1);
        perror("mkfifo() error");
        exit(-1);
    }
     //创建子进程
    childpid = fork();
    if(childpid == 0)
    {
        readfd = open(FIFO1,O_RDONLY,0);
        writefd = open(FIFO2,O_WRONLY,0);
        printf("Server input a message: ");
        gets(buf);
        write(writefd,buf,strlen(buf));
        read(readfd,buf,100);
        printf("Server received a message from Client: %s\n",buf);
        exit(0);
    }
    if(childpid == -1)
    {
        perror("frok() error");
        exit(-1);
    }
     //防止死锁,注意顺序
    writefd = open(FIFO1,O_WRONLY,0);
    readfd = open(FIFO2,O_RDONLY,0);
    read(readfd,buf,100);
    printf("Client received a message form Server: %s\n",buf);
    printf("Client input a mesage: ");
    gets(buf);
    write(writefd,buf,strlen(buf));
    waitpid(childpid,NULL,0);
    close(readfd);
    close(writefd);
    unlink(FIFO1);
    unlink(FIFO2);
    return 0;
}


无亲缘关系:

server.c

//server进程 server.c 
#include "fifo.h"

int main()
{
    int readfd,writefd;
    pid_t   childpid;
    char buf[100];
    memset(buf,0,100);
    //创建FIFO
    if((mkfifo(FIFO1,FILE_MODE) < 0) && (errno != EEXIST))
    {
        perror("mkfifo() error");
        exit(-1);
    }
    if((mkfifo(FIFO2,FILE_MODE) < 0) && (errno != EEXIST))
    {
        unlink(FIFO1);
        perror("mkfifo() error");
        exit(-1);
    }
    readfd = open(FIFO1,O_RDONLY,0);
    writefd = open(FIFO2,O_WRONLY,0);
    printf("Server input a message: ");
    gets(buf);
    write(writefd,buf,strlen(buf));
    read(readfd,buf,100);
    printf("Server received a message from Client: %s\n",buf);
    return 0;
}

client.c

//client进程 client
#include "fifo.h"

int main()
{
    int readfd,writefd;
    pid_t   childpid;
    char buf[100];
    memset(buf,0,100);
    //创建FIFO
    if((mkfifo(FIFO1,FILE_MODE) < 0) && (errno != EEXIST))
    {
        perror("mkfifo() error");
        exit(-1);
    }
    if((mkfifo(FIFO2,FILE_MODE) < 0) && (errno != EEXIST))
    {
        unlink(FIFO1);
        perror("mkfifo() error");
        exit(-1);
    }

     //防止死锁,注意顺序
    writefd = open(FIFO1,O_WRONLY,0);
    readfd = open(FIFO2,O_RDONLY,0);
    read(readfd,buf,100);
    printf("Client received a message form Server: %s\n",buf);
    printf("Client input a mesage: ");
    gets(buf);
    write(writefd,buf,strlen(buf));
    close(readfd);
    close(writefd);
    unlink(FIFO1);
    unlink(FIFO2);
    return 0;
}


    (3) 信号(signal):信号是比较复杂的通信方式,用于通知接收进程有某种事情发生,除了用于进程间通信外,进程还可以发送信号给进程本身;Linux除了支持UNIX早期信号语义函数signal外,还支持语义符合POSIX.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD即能实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数的功能);
    (4) 共享内存(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它,为了实现更安全通信,往往还与信号灯等同步机制共同使用。
    (5) 消息队列(message queue):消息队列是消息的连接表,包括POSIX消息对和System V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能成该无格式字节流以及缓冲区大小受限等缺点;
    (6) 信号量(semaphore):信号量主要作为进程间以及同进程不同线程之间的同步手段;
    (7) 套接字(Socket):它是更为通用的进程间通信机制,可用于不同机器之间的进程间通信。起初是由UNIX系统的BSD分支开发出来的,但现在一般可以移植到其他类UNIX系统上:Linux和System V的变种都支持套接字。

参考资料:http://blog.youkuaiyun.com/henryxuzhou/article/details/17750907



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值