C语言:进程间通信

管道

又内核提供,单工,自同步机制。使用广泛。(管道必须凑齐读写双方才能够运行。)

匿名管道

/home/qt/c/linux_c/ipc/pipe

看不到管道的名称,适合有亲缘关系的进程通信。

pipe.c

       int pipe(int fildes[2]);
 

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

#define BUFSIZE 1024
int main()
{
    pid_t pid;
    int ret;
    int pd[2];
    char buf[BUFSIZE];
    int len;
    ret = pipe(pd); // 0是读,1是写
    if(ret<0)
    {
        perror("pipe()");
        exit(1);
    }
    pid = fork();
    if(pid == 0)
    {
        //child read   
        close(pd[1]);
        puts("Child Begin");
        len = read(pd[0],buf,BUFSIZE); //如果父进程不写,那么会阻塞等待
        write(1,buf,len);
        close(pd[0]);
        puts("Child End");
        exit(1);
        puts("Exit");
    }
    else if(pid >0)
    {
        sleep(1);
        // parent write
        close(pd[0]);
        write(pd[1],"Hello\n",6);
        close(pd[1]);
//        wait(NULL);
        exit(1);
    }

    return 0;
}


player.c 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BUFSIZE 1024
int main()
{
    pid_t pid;
    int ret;
    int pd[2];
    char buf[BUFSIZE];
    int len;
    ret = pipe(pd); // 0是读,1是写
    if(ret<0)
    {
        perror("pipe()");
        exit(1);
    }
    pid = fork();
    if(pid == 0)
    {
        //child read   
        close(pd[1]);
        dup2(pd[0],0); //将管道重定向到标准输入。
        close(pd[0]);
        int fd = open("/dev/null",O_RDWR);
        dup2(fd,1);//关闭文件描述符1,然后文件描述符1执行 /dev/null
        dup2(fd,2);

        execl("usr/bin/mpg123","mpg123","-",NULL);
        perror("excel");
        exit(0);
    
    }

    else if(pid >0)
    {
        close(pd[0]);
        //父进程从网上收数据,在管道中写。
        

        close(pd[1]);
        wait(NULL);
        exit(0);
    }

    return 0;
}


命名管道

mkfifo namedfifo可以创建一个命名管道,文件类型为P

可以看到管道的名称,适合非亲缘关系的进程通信。

mkfifo

       int mkfifo(const char *pathname, mode_t mode);
 

XSI ->SysV

XSI(System Interface and Headers),代表一种Unix系统的标准 XSI IPC,依托标识符和键来实现的,如同管道靠文件描述符来实现一样。包含了三种通信机制:消息队列,信号量,共享内存。

ipcs命令:可以看到 消息队列,信号量数组,共享内存的信息。

key:ftok();拿到同一个key值。

       key_t ftok(const char *pathname, int proj_id); //hash的原串+杂志。

xxxget xxxop xxxctl
xxx -> msg  sem shm

 消息队列

消息队列有缓存数据的能力,通过ulimit -a查看

主动端:先发包的一方。
被动端:先收包的一方。

/home/qt/c/linux_c/ipc/xsi/msg/basic

       int msgget(key_t key, int msgflg);
       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);
       int msgctl(int msqid, int cmd, struct msqid_ds *buf);

proto.h
#ifndef PROTO_H
#define PROTO_H

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>


#define KEYPATH "/etc/services"
#define KEYPROJ 'a'
#define NAMESIZE 1024


struct msg_st
{
    long mtype;
    char name[NAMESIZE];
    int math;
    int chinese;

};


#endif 
snder.c
#include <stdlib.h>
#include <stdio.h>
#include "proto.h"


int main()
{
    key_t key;

    key = ftok(KEYPATH,KEYPROJ);
    if(key <0)
    {
        perror("ftok()");
        exit(1);
    }
    int msgid;

    msgid = msgget(key,0);
    if(msgid <0)
    {
        perror("msgget");
        exit(1);
    }
    struct msg_st sbuf;
    sbuf.mtype = 1;
    sprintf(sbuf.name,"%s","hello msg");
    sbuf.math = rand()%100;
    sbuf.chinese = rand()%100;

    int len;
    len = msgsnd(msgid,&sbuf,sizeof(sbuf) - sizeof(long),0);
    if(len <0)
    {
        perror("msgsnd()");
        exit(1);
    }
    puts("OK!");
//    msgctl();

    return 0;
}
recv.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "proto.h"


int main()
{
    key_t key;

    key = ftok(KEYPATH,KEYPROJ);
    if(key <0)
    {
        perror("ftok()");
    }
    int msgid;
    msgid = msgget(key,IPC_CREAT|0600 );
    if(msgid<0)
    {
        perror("msgget");
    }
    struct msg_st rbuf;
    int len;
    while(1)
    {
        len = msgrcv(msgid,&rbuf,sizeof(rbuf)-sizeof(long),0,0 );
        if(len <0)
        {
            perror("msgrcv");
        }
        printf("NAME  = %s \n",rbuf.name);
        printf("MATH  = %d \n",rbuf.math);
        printf("CHINESE = %d \n",rbuf.chinese);
    }
    msgctl(msgid,IPC_RMID,NULL);

    return 0;
}

命令:ipcrm 删除上述程序中产生的消息队列。ipc -q (msqid号)

消息队列ftp协议

#ifndef PROTO_H
#define PROTO_H

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>


#define KEYPATH "/etc/services"
#define KEYPROJ 'a'
#define PATHSIZE 1024
#define DATASIZE 1024
enum
{
    MSG_PATH =1,
    MSG_DATA,
    MSG_EOT
}

typedef struct msg_path_st
{
    long mtype; //must be MSG_PATH
    char path[PATHSIZE]; //ASCII带尾0的串

}msg_path_t;

typedef struct msg_data_st
{
    long mtype;
    char data[DATAMAX];
    int datalen;

}msg_data_t;

typedef struct msg_eot_st
{
    long mtype;
}msg_eot_t;

union msg_s2c_un
{
    long mtype; //提取公因子。
    msg_data_t datamsg;
    msg_eot_t  eotmsg;
};

#endif




#ifndef PROTO_H
#define PROTO_H

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>


#define KEYPATH "/etc/services"
#define KEYPROJ 'a'
#define PATHSIZE 1024
#define DATASIZE 1024
enum
{
    MSG_PATH =1,
    MSG_DATA,
    MSG_EOT
}

typedef struct msg_path_st
{
    long mtype; //must be MSG_PATH
    char path[PATHSIZE]; //ASCII带尾0的串

}msg_path_t;

typedef struct msg_s2c_st
{
    long mtype; /* 用MSG_DATA或者MSG_EOT进行判断*/
    char data[DATAMAX];
    int datalen;
    /*
    datalen >0 :data包
    datalen =0 :eot包
    */
}msg_data_t;

#endif




信号量

路径:c/linux_c/ipc/xsi/sem,P(取资源)V(还资源)操作。

       int semget(key_t key, int nsems, int semflg);
   int semop(int semid, struct sembuf *sops, size_t nsops);
       int semtimedop(int semid, struct sembuf *sops, size_t nsops,
                      const struct timespec *timeout);
       int semctl(int semid, int semnum, int cmd, ...);
 

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>


#define FILENAME  "/tmp/out"
#define PROCNUM (10)

static int semid;

static void P()
{
    struct sembuf op;
    op.sem_num = 0;
    op.sem_op = -1;
    op.sem_flg = 0;

    int ret;
    ret = semop(semid,&op,1);
    while(ret<0)
    {
        if(errno != EINTR || errno != EAGAIN)
        {
            perror("semop");
            exit(1);
        }
    }

}

static void V()
{
    struct sembuf op;
    int ret;
    op.sem_num = 0;
    op.sem_op = 1;
    op.sem_flg = 0;
    ret = semop(semid,&op,1);
    if(ret<0)
    {
        perror("semop");
        exit(1);
    }
}

void func_add(void);

int main()
{
    pid_t pid;
    int i,j,mark;
    int err; 

    semid = semget(IPC_PRIVATE,1,0600);   //匿名ipc,用于父子进程通信
    if(semid <0)
    {
        perror("semget");
        exit(1);
    }
    int ret;
    ret = semctl(semid,0,SETVAL,1);//设置数组0下标的值为1.
    if(ret<0)
    {
        perror("semctl");
        exit(1);
    }

    for(i =0;i
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值