善用搜索

进程间的几种通信方式教程

1、匿名管道pipe

2、命名管道FIFO

3、XSI IPC

3.1、消息队列

3.2、信号量

3.3、共享存储

4、网络套接字socket

1、匿名管道pipe

===============================

匿名管道是半双工的,并且只能在具有公共祖先的两个进程之间使用。通常一个管道由一个进程创建,在进程调用fork之后,这个管道就能在父进程和子进程之间使用了。管道创建时会创建两个文件描述符,其中fd[0]为读而打开,fd[1]为写而打开。

#include "apue.h"

int main()
{
    int n;
    int fd[2];
    pid_t pid;
    char line[MAXLINE];
    
    if (pipe(fd) < 0) {
        err_sys("pipe error");
    }
    if ((pid = fork()) < 0) {
        err_sys("fork error");
    }
    else if (pid > 0) {
        close(fd[0]);
        write(fd[1], "hello world\n", 12);
    }
    else {
        close(fd[1]);
        n = read(fd[0], line, MAXLINE);
        write(STDOUT_FILENO, line, n);
    }
    exit(0);
}

2、命名管道FIFO

===============================

pipe只能在两个相关的进程之间使用,而命名管道FIFO则可以在两个不相关的进程之间使用,使用的范围更广。 使用FIFO时,首先需要使用mkfifo来创建它,创建之后,可以使用文件的相关函数open、read、write、close等函数像普通文件一样操作这个命名管道。

从FIFO读数据的进程:

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO "/tmp/myfifo"
 
int main(int argc,char** argv)
{
     char buf_r[100];
     int  fd;
     int  nread;
     
     /* 创建FIFO */
     if ((mkfifo(FIFO, O_CREAT|O_EXCL) < 0)&&(errno != EEXIST)) 
     {
        printf("cannot create fifoserver\n");
     }
         
     printf("Preparing for reading bytes...\n");     
     memset(buf_r, 0, sizeof(buf_r));
     fd = open(FIFO, O_RDONLY|O_NONBLOCK, 0);
     if (fd == -1)
     {
         perror("open");
         exit(1);    
     }
     while (1)
     {
         memset(buf_r, 0, sizeof(buf_r));         
         if ((nread = read(fd, buf_r, 100)) == -1) 
         {
             if(errno == EAGAIN)
             {
                printf("no data yet\n");
             }                 
         }
         printf("read %s from FIFO\n", buf_r);
         sleep(1);
     }    
     pause();
     unlink(FIFO);
}

写消息到FIFO的进程:

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO_SERVER "/tmp/myfifo"
 
int main(int argc,char** argv)
{
    int fd;
    char w_buf[100];
    int nwrite;
    
    fd = open(FIFO_SERVER, O_WRONLY | O_NONBLOCK, 0);
    if (fd == -1)
    {
        if (errno == ENXIO)
        {
            printf("open error; no reading process\n");
        }            
    }
    
    if (argc == 1)
    {
        printf("Please send something\n");
    }
        
    strcpy(w_buf, argv[1]);
    if ((nwrite = write(fd, w_buf, 100)) == -1)
    {
        if (errno == EAGAIN)
        {
            printf("The FIFO has not been read yet.Please try later\n");
        }            
    }
    else
    {
        printf("write %s to the FIFO\n", w_buf);
    }         
}

3、XSI IPC

==============================

信号量、消息队列、共享存储这种IPC被称作XSI IPC,这三种IPC中,内核中都有一个非负整数的标识符加以引用。标识符是IPC的内部名,为此,每个IPC对象都与一个键(key)相关联,将这个键作为该对象的外部名。可以调用ftok函数,传入路径名和项目ID创建一个键,然后可以在信号量,消息队列和共享存储之间使用。

#include <sys/ipc.h>

key_t ftok(const char *path, int id);

XSI IPC的几个缺点:

3.1、消息队列

#include <sys/msg.h>

// 创建一个消息队列
int msgget(key_t, int flag);

// 将数据放到消息队列中
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);

// 从消息队列中取数据
int msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);

3.2、信号量

信号量与pipe、FIFO、消息队列同,它时一个计数器,用于多个进程提供对共享数据的访问,即P操作V操作

#include <sys/sem.h>

// 创建信号量
int semget(key_t key, int nsems, int flag);

// 设置信号量的值
int semctl(int semid, int semnum, int cmd, .../* union semun arg */);

// 对信号量进行P操作和V操作
int semop(int semid, struct sembuf semoparray[], size_t nops);

信号量、记录锁、互斥量的比较

3.3、共享存储

共享存储允许两个或者多个进程共享一个给定的存储区,数据不用在多个进程间复制,因此这是最快的一种IPC。通常信号量用于同步共享存储的访问,但是也可以使用记录锁或者互斥量。

#include <sys/shm.h>

// 获取一个共享存储标识符
int shmget(key_t key, size_t, int flag);

// 对共享存储的操作,包括获取共享存储的属性、删除共享存储等
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

// 共享存储连接到进程的地址空间中
void *shmat(int shmid, const void *addr, int flag);

// 从地址空间中解锁共享存储
int shmdt(const void *addr);

4、网络套接字socket

==================================

发表评论
退出移动版