进程间通信

一、管道(popen和pclose)

这两个函数实现的操作是:创建一个管道,fork一个子进程,关闭管道的不使用端,exec一个cmd命令,等待命令终止。

函数popen先执行fork,再调用exec执行command,并且返回一个标准的I/O文件指针。

①如果type是“r”,则文件指针连接到cmd的标准输出。

②如果type是“w”,则文件指针连接到cmd的标准输入。

 

二、命名管道FIFO

FIFO IPC机制:利用文件系统中系统文件来标识的。可以用mkfifo命令创建一个FIFO文件:

mkfifo tube

ls -l tube

FIFO文件在磁盘上没有数据块,仅用来标识内核中的一条通道,各进程可以打开这个文件进行read/write,实际上是在读写内核通道(根本原来在于file结构体所指向的read,write函数和常规文件不一样),这样就实现了进程间通信。

二、共享内存

1.共享存储

允许两个或多个进程共享一给定的存储区。因为数据不需要在客户机和服务器之间复制。

2.调用第一个函数是shmget,获得一个指定大小的共享存储标识符。

①key:用来标识共享内存size参数该共享存储段最小值,如果正在创建一个新段(一般在服务器),必须指定size。如果正在存放一个现存的段,将size指定为0。

②shmflg:IPC_CREATE和IPC_EXCL,最为重要的是shmflg中指明访问权限,跟open的mode参数一样。否则出现permission denied错误。

③返回:若成功则为共享内存ID,出错则为-1。

④key由ftok()生成。pathname必须为调用进程可以访问的。pathname和proj_id共同组成一个key。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>


int main(void) {
    key_t key = ftok("./9_1readfifo.c", 9);
    if (key < 0) {
        perror("ftok");
        exit(1);
    }
    printf("key=0x%x\n", key);

    int shmid = shmget(key, 20, IPC_CREAT  | 0666);
    if (shmid < 0) {
        perror("shmget");
        exit(1);
    }
    printf("shmid=%d\n", key);
    return 0;
}

3.调用一旦创建一个共享存储段,进程就可调用shmat将其连接到它的地址空间中。

①返回:若成功则为指向共享存储段的指针,出错则为-1.

②共享存储段连接到调用进程的哪个地址上与addr参数以及flag中是否指定SHM_RND位有关:

如果addr=NULL:此段连接到由内核选择的第一个可用地址上。

如果addr非NULL,并没有指定SHM_RND:此段连接到addr指定的地址上。

如果addr非0,并且指定SHM_RND:此段连接到addr-(addr mod SHMLBA)表示的地址上。

SHM_RND:取整。

SHM_LBA:低边界地址倍数,总是2的乘方。

该算式将地址向下取最近1个SHMLBA的倍数。

③一般指定addr=0,以便由内核选择地址。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>


int main(void) {
    key_t key = ftok("./9_1readfifo.c", 9);
    if (key < 0) {
        perror("ftok");
        exit(1);
    }
    printf("key=0x%x\n", key);

    int shmid = shmget(key, 20, IPC_CREAT  | 0666);
    if (shmid < 0) {
        perror("shmget");
        exit(1);
    }
    printf("shmid=%d\n", key);

    void *shmp = shmat(shmid, NULL, 0);
    if (shmp < 0) {
        perror("shmat");
        exit(1);
    }
    printf("shmp=%p\n", shmp);
    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        exit(1);
    }
    if (pid) {
        //parent process
        while (1) {
            scanf("%s", shmp);
            if (!strcmp(shmp, "quit")) break;
        }
        wait(NULL);
    } else {
        //child process
        while (1) {
            if (!strcmp(shmp, "quit")) break;
            if (shmp) {
                printf("child read %s\n", shmp);
                bzero(shmp, 20);
            }
            sleep(1);
        }
    }
    shmdt(shmp);
    return 0;
}

4.调用当对共享存储段的操作已经结束时,则调用shmdt脱接该段。

(不从系统中删除其标识符以及其数据结构。该标识符依然存在,直到某个进程调用shmctl带命令IPC_RMID特地删除它)

shmaddr参数:以前调用shmat时返回值:返回成功为0,错误为-1.

5.调用shmctl对共享存储段执行多种操作

cmd参数指定下列5种命令中一种,使其在shmid指定的段上执行:

①IPC_STAT:对此段取shmid_ds结构,并存放在由buf指向的结构中。

②IPC_SET:按buf指向的结构中的值设置与该段相关的结构中的以下三个字段:shm_perm.uid, shm_perm.gid, shm_perm.mode。

③IPC_RMID:从系统中删除该共享存储段。

④ISHM_LOCK:锁住共享存储段。由超级用户执行。

⑤SHM_UNLOCK:解锁共享存储段。由超级用户执行。

三、消息队列

1.系统内核维护一个存放消息的队列,不同用户可以向队列中发送信息或者从队列中接收消息。

系统创建或获取消息队列

 创建消息队列或者获取获取消息队列。

参数:

①key:使用ftok()获取到的key。

②mode:IPC_CREAT|0666

返回:消息队列的ID。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/msg.h>

int main() {
    key_t key = ftok("./tube", 9);
    printf("mqid=%#x\n", key);
    int mqid = msgget(key, IPC_CREAT | 0666);
    printf("mqid=%d\n", mqid);
    return 0;
}

2.往队列里发送一条消息。此操作被中断后不会被重启(信号处理中SA_RESTART)

参数:

①msgid:消息队列的id。

②msgp:消息:通常为下面的结构体

③msgsz:消息的长度,指的是消息数据长度。

④msgflg:IPC_NOWAIT(不阻塞) ,MSG_EXCEPT(接收不检测mtype),MSG_NOERROR(消息数据过长时会截断数据)

返回:0:成功,-1:失败。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/msg.h>

#define MSGLEN 20

typedef struct msgbuf
{
    long mtype;
    char mtext[MSGLEN];
}MSG;


int main() {
    key_t key = ftok("./tube", 9);
    printf("mqid=%#x\n", key);
    int mqid = msgget(key, IPC_CREAT | 0666);
    printf("mqid=%d\n", mqid);

    MSG msg;
    msg.mtype = 1;
    strncpy(msg.mtext, "how are you?\n", MSGLEN);
    msgsnd(mqid, &msg, MSGLEN, 0);

    msg.mtype = 2;
    strncpy(msg.mtext, "haha\n", MSGLEN);
    msgsnd(mqid, &msg, MSGLEN, 0);
    return 0;
}

msgrcv:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/msg.h>

#define MSGLEN 20

typedef struct msgbuf
{
    long mtype;
    char mtext[MSGLEN];
}MSG;


int main() {
    key_t key = ftok("./tube", 9);
    printf("mqid=%#x\n", key);
    int mqid = msgget(key, IPC_CREAT | 0666);
    printf("mqid=%d\n", mqid);

    MSG msg;
    msgrcv(mqid, &msg, MSGLEN, 2, 0);
    printf("msg.type=%ld\nmsg,text=%s\n", msg.mtype, msg.mtext);

    msgrcv(mqid, &msg, MSGLEN, 1, 0);
    printf("msg.type=%ld\nmsg,text=%s\n", msg.mtype, msg.mtext);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值