进程间通信

2017-11-13  本文已影响0人  Yojiaku

两种方式:1. 管道 2. 消息队列

管道

函数介绍

[图片上传失败...(image-700873-1510553414685)]

shiyan2_1.c

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

int main()
{
    int fd[2] = {1, 1};
    pipe(fd);
    int read_fd = fd[0];
    int write_fd = fd[1];
    char readBuffer[255];
    char fileBuffer[255];

    FILE *fp;
    pid_t child1 = fork();
    if(child1 < 0) printf("Failed to create a process.\n");
    else if(child1 == 0){
        if((fp=fopen("./text.txt", "wt+")) == NULL) printf("open file error!\n");
        else{
            fprintf(fp, "This is testing for fprintf...\n");            
        }
        fclose(fp);

        char pipeStr[] = "OK";
        if(write(write_fd, pipeStr, strlen(pipeStr))) exit(0);
        else{
            printf("write error\n");
            exit(1);
        }
    }

    pid_t child2 = fork();
    if(child2 < 0) printf("Failed to create a process.\n");
    else if(child2 == 0){
        if(read(read_fd, readBuffer, sizeof(readBuffer))){
            if(strcmp(readBuffer, "OK") == 0){
                if((fp=fopen("./text.txt", "r")) == NULL) printf("open file error!\n");
                else{
                    fgets(fileBuffer, sizeof(fileBuffer), (FILE*)fp);
                    printf("%s\n", fileBuffer);
                }
                fclose(fp);
                exit(0);
            }else{
                printf("Sorry.\n");
                exit(1);
            }
        }else{
            printf("read error\n");
            exit(1);
        }
        
    }

    for(int i=0; i<=1; i++)
    {
        // 父进程等待子进程退出
        pid_t cpid = wait(NULL);
        printf("No.%d process, its PID is %d exits\n", i, cpid);
    }

    return 0;
}

消息队列
消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向中按照一定的规则添加新信息;对消息队列有读权限的进程则可以从消息队列中读走消息。消息队列是随内核持续的。

什么叫随“内核持续”呢?
即只有在内核重启或者显示删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构(struct ipc_ids msg_ids) 位于内核中,系统中的所有消息队列都可以在结构msg_ids中找到访问入口。

消息队列

struct msgbuf
{
    long mytype;  // 存储消息类型
    unsigned char mytext[128]; // 存储消息内容
};

其中 mytype 成员代表消息类型,从消息队列中读取消息的一个重要依据就是消息的类型;mytext 成员是消息内容,当然长度不一定是128.
因此,对于发送消息来说,首先预置一个msgbuf缓冲区并写入消息类型和内容,调用相应的发送函数即可;对读取消息来说,首先分配一个msgbuf缓冲区,然后把消息读入该缓冲区即可。

函数介绍——第一种介绍方式

  1. 文件名到键值
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(char *pathname, char proj);

它返回与路径pathname相对应的一个键值。该函数不直接对消息队列操作,但在调用ipc(MSGGET,...)或megget()来获得消息队列描述字前,往往要调用该函数。典型的调用代码是:

key = ftok(path_ptr, 'a');
ipc_id = ipc(MSGGET, (int)key, flags, 0, NULL, 0);
...
  1. Linux为操作系统V进程间通信的三种方式(消息队列,信号灯,共享内存区)提供了一个统一的用户界面:
int ipc(unsigned int call, int first, int second, int third, void *ptr, long fifth);

下面介绍这四种操作:

  1. 系统V消息队列API
    需要包含下列头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

1)int msgget(key_t key, int msgflg)
参数key是一个键值,由ftok获得;msgflg是一些标志位。该调用返回与键值key相对应的消息队列描述子。
在以下两种情况,该调用将创建一个新的消息队列:

参数msgflg可以为:IPC_CREAT, IPC_EXCL, IPC_NOWAIT
调用返回:成功返回消息队列描述字,否则-1.
PS:参数key设置为常数 IPC_PRIVATE 并不意味着其他进程不能访问该消息队列,只意味着即将创建新的消息队列。

2)*int msgrcv(int msqid, struct msgbuf msgp, int msgsz, long msgtyp, int msgflg)
该系统调用从msgid代表的消息队列中读取一个消息,并把消息存储在msgp指向的msgbuf结构中。
msqid为消息队列描述字;消息返回后存储在msgp指向的地址,msgsz制定msgbuf的mtext成员的长度(即消息内容的长度),msgtyp为请求读取的消息类型;读西欧系标识msgflg可以为以下几个常值的或:

msgrcv()解除阻塞的条件:

调用返回:成功返回读出消息的实际字节数,否则返回-1.

3)*int msgsnd(int msqid, struct msgbuf msgp, int msgsz, int msgflg)
向msgid代表的消息队列发送一个消息,即将发送的消息存储在msgp执行的msgbuf结构中,消息的大小由msgsz决定。
对发送消息来说,有意义的msgflg标识为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待。造成msgsnd()等待的条件有两种:

msgsnd()解除阻塞的条件:

调用返回:成功0,失败-1.

4)*int msgctl(int msqid, int cmd, struct msqid_ds buf)
该系统调用对由msqid标识的消息队列执行cmd操作,共有三种cmd操作:IPC_STAT、IPC_SET 、IPC_RMID。

调用返回:成功返回0,否则返回-1。

函数介绍——第二种介绍方式(实验)

上一篇 下一篇

猜你喜欢

热点阅读