进程间的通信

一. 管道分为有名管道和无名管道

1. 无名管道:

                有关无名管道的函数:(管道文件的读写可以用文件IO来读写)

int fd[2];    //int型的数组,大小为2,用来存放无名管道的文件描述符
int p = pipe[fd];    //pipe为无名管道的创建,创建无名管道的读端fd[0]和写段fd[1]的文件描述符
if(-1 == p)
{
    perror(“pipe”);
    return -1;
}

write(fd[1],”要写入的数据”,数据的大小);  //从写端写入  数据到管道


char str[64] = {0};    


read(fd[0],str,sizeof(str));    //从管道的读端读取数据
printf(“%s\n”,str);

无名管道的特点:

a、没有名字,因此无法使用open()打开

b、只能用于亲缘进程间(如父子进程、兄弟进程、祖孙进程等)通信

c、半双工工作方式,读写端是分开的,pipefd[0]为读端,pipefd[1]为写端

d、是一种特殊的文件,只存在内存中,由内核进行管理

e、对于它的读写可以使用文件IO如read、write函数

f、无名管道的操作属于一次性操作,如果对无名管道进行读操作,数据会被全部读走

例:

同一进程中两个线程的通信:

int fd[2];  
int p = pipe[fd];   
if(-1 == p)
{
    perror(“pipe”);
    return -1;
}
Pid_t pid = fork();    //创建一个子线程

4. 共享内存(shm)

        1.通过ftok获取key号

ftok的第一个参数是一个文件的路径名称.一般在应用系统中,使用$HOME或者应用系统的根目录作为它的值.这样产生的key_t就不会与系统中其他的软件和系统的相同了,从而避免造成冲突. (当以文件为第一个参数时,如果文件的大小发生变化,生成的Key也会响应变化,应注意 )

key_t key = ftok(“\”,1);    //获取key号
if(-1 == key)
{
    Perror(“ftok”);
    return -1;
}

        2.创建共享内存得到共享内存的id号

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

第一个参数就是ftok的返回值key;第二个参数是创建的共享内存的大小,第三个参数共享内存的权限

int shmid = shmget(key,1024,IPC_CREAT|0666);    // 通过key来创建共享内存,获取shmid号
if(shmid == -1)
{
    Perror(“shmget”);
    return -1;
}

        3.映射共享内存,得倒共享内存的地址

void *shmat(int shmid, const void *shmaddr, int shmflg);

第一个参数是共享内存的id,第二个参数一般写NULL,代表让系统自己分配空间,第三个参数:0代表可读可写,SHM_RDONLY代表只读

char * p = shmat(shmid,NULL,0);    //映射共享内存得倒共享内存的地址,失败返回NULL
If(NULL == p)
{
    perror(“shmat”);
    return -1;
}

        4.创建进程,直接用共享内存进行传输数据

Pid_t pid = fork();
if(pid < 0)
{
    perror(“fork”);
    return -1;
}
else if(pid == 0)
{
    while(1){
    char str[32] = {0};
    strcpy(shat,str);    //写入数据
    if(strncmp(str,”q”,1) == 0)    //设置结束条件
    {
        break ;
    }
    memset(str,0,sizeof(str));    //清空数组的数据
    }
}
else{
    while(1){
    waitpid(-1,NULL,WNOHANG);    //等待子进程结束,无阻塞
    printf(“shat = %s\n”,shat);    //将内存中的数据打印
    if(strncmp(shat,”q”,1) == 0)    //设置结束条件
    {
        break ;
    }
    }
}

        5.解除断开映射

       int shmdt(映射后的地址):卸载/断开共享内存
当进程不需要此共享内存时,就需要去断开。该函数并不删除所指定的共享内存区,而是将之前用shmat函数连接好的共享内存区脱离目前的进程。

int ret = shmdt(shat);
If(ret == -1)
{
    perror("shmdt”);
    return -1;
}

        6.删除共享的内容

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

第一个参数:共享内存的ID。第二个参数:设置为IPC_RMID时表示可以删除共享内存。第三个参数:设置为0即可。

int ctl = shmctl(shmid,IPC_RMID,NULL);
If(ctl == -1)
{
    perror(“shmctl”);
    return -1;
}

5.消息队列(msg)

        1.获取key-----ftok()

key_t key = ftok(“\”,10);    //获取key号
if(-1 == key)
{
    Perror(“ftok”);
    return -1;
}

        2.创建消息队列

msgget:创建或打开一个消息队列

参数:

  key: key值

  msgflg:  IPC_CREAT|0666

返回值:  

  成功:msgid值

  失败:-1

IPC_CREAT:表明新创建一个消息队列。

int msgid =msgget(key,IPC_CREAT | 0666);    //msgget创建消息队列,成功就返回该消息队列的id,失败返回-1;
if(-1 == msgid)
{
    Perror(“msgget“);
    return -1;
}

      3.进程间通信--信息的发送

int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg);    

功能:发送数据  

参数:

  msgid: msgid值

  msgp:  &msg (结构体变量的地址)

  msgsz: 消息正文的长度 sizeof(msg) - sizeof(long)

  msgflg:

IPC_NOWAIT: 非阻塞

        0 : 阻塞

返回值:

    成功: 0

    失败:-1

pid_t pid = fork();    //创建子进程
 if(pid < 0)
{
    perror(“fork”);
    return -1;
}
else if(pid == 0)
{
    //子进程发送消息
    struct msgbuf msg;    //定义一个msgbuf类型的结构体变量
    char str[64] = {0};
    msg.mtype = 10;    //信号的类型定义为10;
    while(1){
        gets(str);    //获取字符串
        strcpy(msg.mtext,str);    //将数据给到msg中保存数据的数组
        //消息的发送
        megsnd(msgid,&msg,sizeof(msg) - sizeof(long),0);
        //退出条件
        if(strncmp(str,”quit”,4) == 0)
        {
            break;
        }
        memset(str,0,sizeof(str));
    }
}

用到的 结构体:

struct msgbuf {

  long mtype;       /* message type, must be > 0 */ 消息的类型

  char mtext[N];    /* message data */ 正文

};

struct msgbuf msg;        //定义一个结构体变量

 4.进程间的通信---信息的接收

ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

功能:接收数据

参数比发送数据的多了一个long msgtyp:消息的类型,这个要跟发送的信息类型一致,不然接收不到

while(1){
       
        waitpid(-1,NULL,WNOHANG);
        //消息的接收
        megrcv(msgid,&msg,sizeof(msg) - sizeof(long),10,0);
        printf(“mtxt = %s\n”,msg.mtext);
        //退出条件
        if(strncmp(str,”quit”,4) == 0)
        {
            break;
        }
        memset(str,0,sizeof(str));
}

5. 删除消息队列 

int msgctl(int msgid, int cmd, struct msqid_ds *buf);        

功能: 控制函数      

参数:

  msgid: msgid值

  cmd: IPC_RMID (删除消息队列)

  buf: NULL

返回值:        

   成功; 0

   失败:-1 ​​​​​​​

int ctl = msgctl(msgid,IPC_RMID,NULL);
If(ctl == -1)
{
    perror(“msgctl”);
    return -1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值