Linux进程间通信

进程间通信(IPC)


管道:

who | wc -l   // who结果写入内核缓存
int pipe(int fds[2]); //两个文件描述符,读和写

一般:

  • fds[0] 为读取管道
  • fds[1] 为对管道写
  • 管道必须读写两端同时打开。

例子:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7     int fds[2]; //fds[0]为读,1为写
  8     if(pipe(fds)==-1)
  9     {
 10         perror("pipe"),exit(1);
 11     }
 12 
 13     pid_t pid = fork();
 14     if(pid == -1)
 15     {
 16         perror("fork"),exit(1);
 17     }
 18     else if(pid==0)     //子进程写
 19     {
 20         close(fds[0]);    //关闭子进程的读端口
 21         write(fds[1],"abcd",4);    //向管道写 abcd
 22         close(fds[1]);  //写完后关闭 写端口
 23         exit(0);    //正常退出
 24     }
 25     else if(pid>0)   //父进程
 26     {
 27         close(fds[1]);   //关闭父进程写端口
 28         char buf[100] = {};
 29         int r = read(fds[0],buf,100);//读的内容
 30         if(r==0)
 31         {
 32             printf("read EOF\n");
 33         }
 34         else if(r==-1)
 35         {
 36             perror("read"),exit(1);
 37         }
 38         else if(r>0)  //读成功
 39         {
 40             printf("%s\n",buf);//打印内容
 41             close(fds[0]);//关闭读端口
 42             exit(0);
 43         }
 44     }
 45 }

命名管道

mkfifo my.p  //创建管道文件 大小为0
int mkfifo()  //创建管道文件
//打开管道文件
    int fd = open(name, O_RDONLY);//读
    int fd = open(name, O_WRONLY);//写
    //read / write 语义和匿名管道一样

消息队列

int msgget(key_t key, int msgflag);
参数说明:
//相当于文件名 ,是在内核创建的
//打开:0;创建:IPC_CREATE | 0644(权限)
功能:用于创建一个新的或者打开一个已有的消息队列
返回值:消息队列的id,相当于文件描述符
头文件:(sys/msg.h sys/ipc.h)
命令查看:(ipcs -q)
删除IPC对象:(ipcrm -Q key)
系统中最多能够创建多少消息队列:

cat /proc/sys/kernel/msgmni
7543

一条消息最多可以装多少字节:

        cat /proc/sys/kernel/msgmni

一个消息队列中所有消息的总字节数:

        cat /proc/sys/kernel/msgmnb

例子:创建消息队列

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

int main()
{
    int msgid = msgget(1357,IPC_CREAT|0644);
    if(msgid==-1){
        perror("msgget"),exit(1);
    }
    printf("msgget ok");
}

// 1357的16进制为0x0000054d

——— 消息队列 ———–
键 ———– msqid 拥有者 权限 已用字节数 消息
0x0000054d – 0 — root – 644 ——- 0 ——- 0


往消息队列中发送数据:

int msgsnd(int id, const void *msgp, size_t len, int flag)
参数说明:
//msgget返回值,要发送的消息在哪里,消息的字节数(不包括channel的大小),0
返回值:成功:0;失败: -1

struct msgbuf{
        long channel;//消息类型(通道号),必须>=1
        //随便,比如自己的消息内容,char mtext[100];
};

例子:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<sys/msg.h>
  5 #include<sys/ipc.h>
  6 
  7 struct msgbuf{
  8     long mtype;
  9     char mtext[1000];
 10 };
 11 
 12 int main(int argc, char* argv[])
 13 {
 14     if(argc!=2)//参数个数不对
 15     {
 16         fprintf(stderr,"usage:%s type\n", argv[0]);
 17         exit(1);
 18     }
 19 
 20     int id = msgget(1357,0);//打开一个已有的消息队列,第二个参数为0
 21     if(id==-1)//打开失败
 22     {
 23         perror("msgget"),exit(-1);
 24     }
 25 
 26     struct msgbuf mb;//创建消息结构体
 27     memset(&mb, 0x00, sizeof(mb));//清空
 28 
 29     mb.mtype = atoi(argv[1]);//将id转换为整形
 30     printf("msg: ");
 31     fgets(mb.mtext, 999, stdin);
 32 
 33     int res = msgsnd(id, &mb, strlen(mb.mtext), 0);//发送消息
 34     if(res==-1)perror("msgsnd"),exit(1);
 35 }

从消息队列中取数据

ssize_t msgrcv(int id, void *msggp, size_t len, long mtype, int flag);

参数说明:
//取出来的消息放到这里 装消息的地方的大小(不包括类型)装哪个类型的消息 0

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<sys/msg.h>
  5 #include<sys/ipc.h>
  6 
  7 struct msbuf{
  8     long mtype;
  9     char mtext[1000];
 10 };
 11 
 12 int main(int argc, char *argv[])
 13 {
 14     if(argc!=2)
 15     {
 16         fprintf(stderr,"usage:%s type\n",argv[0]);
 17         exit(-1);
 18     }
 19 
 20     int id = msgget(1357,0);//打开消息队列
 21     if(id==-1)perror("msgget"),exit(-1);
 22 
 23     struct msbuf mb;
 24     memset(&mb,0x00,sizeof(mb));
 25 
 26     if(msgrcv(id,&mb,1000,atoi(argv[1]),0)==-1)//从消息队列读取消息内容
 27         perror("msgrcv"),exit(-1);
 28 
 29     printf("%s\n",mb.mtext);
 30 }

共享内存

头文件:ipc和shm
创建或打开共享内存:

shmget(key_t key, size_t size,int flag);  

参数说明:
//共享内存段大小 //创建IPC_CREATE|0644,打开为0

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<sys/ipc.h>
  5 #include<sys/shm.h>
  6 
  7 struct stu{
  8     int id;
  9     char name[20];
 10 };
 11 
 12 int main()
 13 {
 14     int shmid = shmget(1234,sizeof(struct stu),IPC_CREAT|0644);
 15     if(shmid == -1)perror("shmget"),exit(-1);
 16     printf("create ok");
 17 }

这里写图片描述


让共享内存和本进程建立关系

void *shmat(int id, char *shmaddr, int flag);

参数说明:
想让操作系统挂到这个地址空间,或者NULL让操作系统自己选择
返回值:实际挂载到的虚拟地址的起始位置

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<sys/ipc.h>
  5 #include<sys/shm.h>
  6 #include<assert.h>
  7 struct stu{
  8     int id;
  9     char name[20];
 10 };
 11 
 12 int main()
 13 {
 14     int shmid = shmget(1234,sizeof(struct stu),0);
 15     if(shmid == -1)perror("shmget"),exit(-1);
 16 
 17     struct stu *p = (struct stu*)shmat(shmid, NULL, 0);
 18     assert(p!=NULL);
 19 
 20     p->id = 1;
 21     strcpy(p->name,"hello");
 22     sleep(3);
 23     shmdt(p);
 24 }

卸载共享内存:

int shmdt(void *shmadr);

删除共享内存:

int shmctl(int id, int cmd, NULL);
第二个参数://IPC_RMID

PV操作

创建或打开信号量:
int semget(key_t key, int nsems, int flag)
参数说明:后两个参数
//信号量集中信号量的个数 //打开:0 创建:IPC_CREAT|0644

例子:

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<string.h>

int main()
{
    int id = semget(1234,1,IPC_CREAT|0644);
    if(id==-1)perror("semget"),exit(-1);
    printf("create ok\n");
}

这里写图片描述


设置信号量初值:

int semctl(int id,
        int semnum, //信号量集中的第几个信号量
        int cmd, //SETVAL
        su);  //这是信号量初值
union semun{
    int val;   //value for setval;
}

例子:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/ipc.h>
  4 #include<sys/sem.h>
  5 #include<string.h>
  6 
  7 union semun{
  8     int val;
  9 };
 10 
 11 int main()
 12 {
 13     int id = semget(1234,0,0);
 14     if(id==-1)perror("semget"),exit(-1);
 15 
 16     union semun su;
 17     su.val = 5;
 18     semctl(id, 0, SETVAL, su);
 19 }

设置完,查看信号量的值:

int semctl(int id,
        int semnum, //信号量集中的第几个信号量
        int cmd, //GETVAL
        0);  

返回值:当前信号量的值
例子:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/ipc.h>
  4 #include<sys/sem.h>
  5 #include<string.h>
  6 
  7 int main()
  8 {
  9     int id = semget(1234,0,0);
 10     if(id==-1)perror("semget"),exit(-1);
 11 
 12     int val = semctl(id,0,GETVAL);
 13     printf("%d\n",val);
 14 }

PV操作:

int semop(int semid, 
        struct sembuf sb[],
        int len);
struct sembuf{
    short sem_num, //信号量的下标
    short sem_op, //1 V;-1 P
    short sem_flag, //为 0
};

P操作:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/ipc.h>
  4 #include<sys/sem.h>
  5 #include<string.h>
  6 
  7 void p(int id)
  8 {
  9     struct sembuf sb[1];
 10     sb[0].sem_num = 0;
 11     sb[0].sem_op = -1;
 12     sb[0].sem_flg = 0;
 13 
 14     semop(id, sb, 1);
 15 }
 16 
 17 int main()
 18 {
 19     int id = semget(1234,0,0);
 20     if(id==-1)perror("semget"),exit(-1);
 21 
 22     p(id);
 23 }

V操作:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/ipc.h>
  4 #include<sys/sem.h>
  5 #include<string.h>
  6 
  7 void v(int id)
  8 {
  9     struct sembuf sb[1];
 10     sb[0].sem_num = 0;
 11     sb[0].sem_op = 1;
 12     sb[0].sem_flg = 0;
 13 
 14     semop(id, sb, 1);
 15 }
 16 
 17 int main()
 18 {
 19     int id = semget(1234,0,0);
 20     if(id==-1)perror("semget"),exit(-1);
 21 
 22     v(id);
 23 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值