[linux专题]基于linux进程间通信

 

目录

1.进程通信方式及对比

2. 通信方式编程

2.1 管道通信

2.2 命名管道通信

2.3 消息队列通信

2.4 信号量通信

2.5 共享内存


1.进程通信方式及对比

序号 通信方式 对比说明
1 管道(pipe) 半双工通信,单向数据流,只能在父子进程间使用。
2 命名管道(named pipe) 半双工通信,允许无亲缘关系进程通信
3 信号量(semophore) 计数器,一种锁机制,用来控制多个进程对共享资源的访问
4 消息队列(message queue) 消息链表存在内核并标识,克服信号传递信息少等问题
5 信号(signal) 用于通知接收进程某个事件的发生
6 共享内存(shared memory) 映射一块能被其他进程访问的内存,速度快,效率高
7 套接字(socket) 不仅允许机器内部,也允许机器间的通信方式。

2. 通信方式编程

2.1 管道通信

管道创建,其中fd[0] 为读端,fd[1]为写端

int pipe(int fd[2]);

 管道使用,见下程序,若需要双向,则可以建立两个管道。

/*pipe_example.c*/

#include 
#include 
#include 
#include 
#include 

void read_pipe(int fd);
void write_pipe(inf fd);

int main(void)
{
    int fd[2];
    pid_t pid;
    int stat_1;

    if (pipe(fd))
    {
        printf("pipe create failed \n");
        exit(1);
    }

    pid = fork();
    if ( pid == -1)
    {
        printf("fork error \n");
        exit(1);
    }
    else if (pid == 0) /*chlid*/
    {
        close(fd[1]);/*关闭写*/
        read_pipe(fd[0]);
        exit(0);
    }
    else /*parent*/
    {
        close(fd[0]);
        write_pipe(fd[1]);
        wait(&stat_1);
        exit(0);
    }

  exit(0);
}

void read_pipe(int fd)
{
    char msg[100];

    read(fd,msg,100);
    printf("read pipe msg :%s",msg); 
}

void write_pipe(inf fd)
{
    char *msg = "my pipe \n";

    write(fd,msg,strlen(msg)+1);
}

2.2 命名管道通信

管道不足之处是,没有名字,只能在亲缘关系的进程间通信,命名管道则克服该限制,提供一个路径名与之关联,以FIFO的文件形式存储于文件系统中,该方式总是先进先出的原则工作。

int mknod(const char *path,mode_t mod,dev_t dev);

int mkfifo(const char *path,mode_t mod);

这里mod参数,用于声明其权限。

/*read_proc.c */
#include 
#include 
#include 
#include 
#include 
#include 

#define FIFO_NAME  "fifo_ag"
#define BUF_SIZE    (1024)

int main(void)
{
    int fd;
    char buf[BUF_SIZE];

    umask(0);
    fd = open(FIFI_NAME,O_RDONLY); /*只读方式*/
    read(fd,buf,BUF_SIZE);
    printf("read named pipe:%s \n",buf);
    close(fd);

    exit(0);
}
/*write_proc.c*/
#include 
#include 
#include 
#include 
#include 
#include 

#define FIFO_NAME    "fifo_ag"
#define BUF_SIZE      (1024)

int main(void)
{
    int fd;
    char buf[BUF_SIZE] = "write named pipe \n";

    umask(0);
    
    if (mkfifo(FIFO_NAME,S_FIFO | 0666) == -1) 
    {
        perror("mkfifo error");
        exit(1);
    } 

    if ((fd = open(FIFO_NAME,O_WRONLY) == -1) /*只写方式*/
    {
        perror("open error");
        exit(1);
    }
    write(fd,buf,strlen(buf)+1);
    
    close(fd);

    exit(0);
}

分别 gcc编译运行,即可得到两个进程传递的消息;若需要两个进程之间全双工通信,则可以建立两个管道。

2.3 消息队列通信

消息队列是存放在内核中的消息链表,只有显示的删除消息队列,才会被真正删除。

消息队列缓存结构

struct msgbuf
{
    long  mtype;
    char mtext[1];
};

消息队列创建,先要创建键值,每个消息队列有唯一的键值。

key_t ftok(const char* pathname,int proj_id);

消息队列根据键值来创建

int msgget(key_t key,int msgflg);

msgflg = IPC_CREATE,若不存在,则在内核创建,否则返回队列描述符

msgflg = IPC_EXCL,若队列已存在,返回-1 报错。

写消息队列

int msgsnd(int msqid,struct msgbuf *msgp,size_t msgsz,int magflg);

读消息队列

int msgrcv(int msqid,struct msgbuf *msgp,size_t msgse,long int msgtyp,int msgflg)

/*fifo_srv.c*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUF_SIZE    (256)
#define PROJ_ID     (32)
#define PATH_NAME   "/tmp"
#define SRV_MSG     (1)
#define CLT_MSG     (2)

int main(void)
{
    struct mymsgbuf
    {
        long msgtype;
        char ctrlstr[BUF_SIZE];
    };msgbuf;

    int qid;
    int msglen;
    key_t msgkey;

    if (msgkey = ftok(PATH_NAME,PROJ_ID)) == -1)
    {
        perror("ftok error");
        exit(1);
    }

    if ((qid = msgget(msgkey,IPC_CREAT|0660)) == -1)
    {
        perror("msgget error\n");
        exit(1);
    }

    while(1)
    {
        printf("server:");
        fgets(msgbuf.ctrlstr,BUF_SIZE,stdin);
        if (strncmp("exit",msgbuf.ctrlstr,4) == 0)
        {
            msgctl(qid,IPC_RMID,MULL);
            break;
        }
        msgbuf.ctrlstr[strlen(msgbuff.ctrlstr)-1] = '\0';
        msgbuf.msgtype = SRV_MSG;
        if (msgsnd(qid,&msgbuf,strlen(msgbuf.ctrlstr)+1,0) == -1)
        {
            perror("server msgsnd error\n");
            exit(1);
        }
        
        if (msgrcv(qid,&msgbuf,BUF_SIZE,CLT_MSG,0) == -1)
        {
            perror("server msgrcv error \n");
            exit(1);
        }
        printf("client : %s \n",msgbuf.ctrlstr);
    }

    exit(0);
}
/*fifo_clt.c*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUF_SIZE    (256)
#define PROJ_ID     (32)
#define PATH_NAME   "/tmp"
#define SRV_MSG      (1)
#define CLT_MSG      (2)

int main(void)
{
    struct mymsgbuf
    {
        long msgtype;
        char ctrlstr[BUF_SIZE];
    }msgbuf;
    
    int qid;
    int msglen;
    key_t msgkey;

    if ((msgkey = ftok(PATH_NAME,PROJ_ID)) == -1)
    {
        perror("ftok error\n");
        exit(1);
    }

    if ((qid = msgget(msgkey,IPC_CREAT|0660)) == -1)
    {
        perror("msgget error\n");
        exit(1);
    }

    while(1)
    {
        if (msgrcv(qid,&msgbuf,BUF_SIZE,SRV_MSG,0) == -1)
        {
            perror("server msgrcv error\n");
            exit(1);
        }

        printf("server : %s\n",msgbuf.ctrlstr);
        printf("client:");
        gets(msgbuf.ctrlstr,BUF_SIZE,stdin);
        if (strncmp("exit",msgbuf.ctrlstr,4 == 0)
        {
            break;
        }

        msgbuf.ctrlstr[strlen(msgbuf.ctrlstr)-1] = '\0';

        msgbuf.msgtype = CLT_MSG;
    
        if (msgsnd(qid,&msgbuf,strlen(msgbuf.ctrlstr)_1,0) == -1)
        {
            perror("client msgsnd error\n");
            exit(1);
        }
    }

    exit(0);
}

先运行server端,再运行client端

2.4 信号量通信

信号量主要用于进程的同步问题,包括临界资源访问。

信号量创建,nsems表示要创建的信号的个数

int segget(key_t key,int nsems,int semflg);

当信号量的值大于0时,表示当前可用资源的数量,小于0,其绝对值表示等待使用该资源的进程个数。信号量的值仅能由PV操作来改变。

int semop(int semid,struct sembuf * sops,size_t nsops);

/*sem_srv.c*/
#include 
#include 
#include 
#include 

#define MAS_RESOURCE    (5)

int main(void)
{
    key_t key
    int semid;
    struct sembuf sbuf = {0,-1,IPC_NOWAIT};
    union semun semopts;

    if ((key = ftok(".",'s')) == -1)
    {
        perror("ftok error\n");
        exit(1);
    }    
    
    if ((semid = semget(key,i,IPC_CREAT|0666)) == -1)
    {
        perror("semget error\n");
        exit(1);
    }

    semopts.val = MAX_RESOURCE;
    
    if (semctl(semid,0,SETVAL,semopts) == -1)
    {
        perror("semctl error\n");
        exit(1);
    }

    while(1)
    {
        if (semop(semid,&buf,1) == -1)
        {
            perror("semop error\n");
            exit(1);
        }
        sleep(3);
    }

    exit(0);
}
/*sem_clt.c*/
#include 
#include 
#include 
#include 

int main(void)
{
    key_t key;
    int semid,semval;
    union semun semopts;

    if ((key = ftok(".",'s')) == -1)
    {
        perror("ftok error\n");
        exit(1);
    }    

    if ((semid = semget(key,1,IPC_CREAT|0666)) == -1)
    {
        perror("semget error\n");
        exit(1);
    }

    while(1)
    {
        if ((semval = semctl(semid,0,GETVAL,0)) == -1)
        {
            perror("semctl error\n");
            exit(1);
        }

        if (semval > 0)
        {
            printf("%d resources can be used \n",semval);
        }
        else
        {
            printf("no resources \n");
            break;
        }
        sleep(3);
    }

    exit(0);
}

2.5 共享内存

共享内存是分配一块能被其他进程访问的内存,维护的结构体如下

struct shmid_ds
{
    struct ipc_perm           shm_perm;       /*

共享内存的操作--创建

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

共享内存的操作--操作,其中shmflg为权限标志

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

共享内存的操作--结束操作

int shmdt(const void *shmaddr);

共享内存的操作--控制操作  (IPC_RMID 删除共享内存区,IPC_SET 设置,IPC_STAT 读取状态)

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


/*shm_opt.c*/

#ifndef __SHM_OPT__
#define  __SHM_OPT__

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SHM_SIZE (1024)

union semun
{
    int                  val;
    struct semid_ds     *buf;
    unsigned short      *array;
};

int creat_sem(const char *pathname,int proj_id,int members,int init_var);
int open_sem(const char *pathname,int proj_id);
int sem_p(int semid,int index);
int sem_v(int semid,int index);
int sem_del(int semid);
int sem_wait(int semid,int index);
int creat_shm(char *pathname,int proj_id,size_t size);

#endif
/*shm_opt.c*/

#include "shm_opt.h"

int creat_sem(const char *pathname,int proj_id,int members,int init_var)
{
    key_t msgkey;
    int   index ,sid;
    union senun semopts;

    if ( msgkey = ftok(pathname,proj_id)) == -1)
    {
        perror("ftok error\n");
        return -1;
    }
    
    if ((sid = semget(msgkey,members,IPC_CREAT|0666)) == -1)
    {
        perror("semget failed \n");
        return -1;
    }

    semopts.val = init_var;

    for (index = 0;index < members;index++)
    {
        semctl(sid,index,SETVAL,semopts);
    }

    return sid;
}

int open_sem(const char *pathname,int proj_id)
{
    key_t key;
    int sid;

    if ((key = ftok(pathname,proj_id)) == -1)
    {
        perror("ftok \n");
        return -1;
    }
    
    if ((sid = semget(key,0,IPC_CREAT|0666)) == -1)
    {
        perror("semget \n");
        return -1;
    }

    return sid;
}

int sem_p(int semid,int index)
{
    struct sembuf buf = {0,-1,IPC_NOWAIT};

    if (index < 0)
    {
        perror("index < 0");
        return -1;
    }

    buf.sem_num = index;

    if (semop(semid,&buf,1) == -1)
    {
        perror("semop \n");
        return -1;
    }

    return 0;
}

int sem_v(int semid,int index)
{
    struct sembuf buf = {0 ,1,IPC_NOWAIT};

    if (index < 0)
    {
        perror("index < 0 \n");
        return -1;
    }

    buf.sem_num = index;

    if (semop(semid,&buf,1) == -1)
    {
        perror("semop \n");
        return -1;
    }
    
    return 0;
}

int sem_del(int semid)
{
    return semctl(semid,0,IPC_RMID);
}

int sem_wait(int semid,int index)
{
    while(semctl(semid,index,GETVAL,0) == 0)
    {
        sleep(1);
    }
    
    return 1;
}

int creat_shm(char *pathname,int proj_id,size_t size)
{
    key_t key;
    int sid;

    if ((key = ftok(pathname,proj_id)) == -1)
    {
        perror("ftok \n");
        return -1;
    }

    if ((sid = shmget(key,size,IPC_CREAT|0666)) == -1)
    {
        perror("shmget error\n");
        return -1;
    }
}
/*shm_wrt.c*/

#include "shm_opt.h"

int main(void)
{
    int semid,shmid;
    char *shmaddr;
    char write_str[SHM_SIZE];

    if ((shmid = creat_shm(".",'m',SHM_SIZE)) == -1)
    {
        exit(1);
    }    

    if ((shmaddr = shmat(shmid,(char*)0,0) == (char*) -1)
    {
        perror("shmat error\n");
        exit(1);
    }

    if ((semid == creat_sem(".",'s',1,1)) == -1)
    {
        exit(1);
    }

    while(1)
    {
        sem_wait(semid,0);
        
        sem_p(semid,0);
        printf("write:");

        fgets(write_str,1024,stdin);
        int len = strlen(write_str) - 1;
        write_str[len] = '\0';
        strcpy(shmaddr,write_str);
        sleep(10);

        sem_v(semid,0);
        sleep(10);
    }

    exit(0);
}
/*shm_read.c*/

#include "shm_opt.h"

int main(void)
{
    int semid,shmid;
    char *shmaddr;
   
    if ((shmid = creat_shm(".",'m',SHM_SIZE)) == -1)
    {
        exit(1);
    }

    if ((shmaddr = shmat(shmid,(char*)0,0)) == (char*)-1)
    {
        perror("shmat error\n");
        exit(1);
    }
    
    if ((semid = sem_open(".",'s')) == -1)
    {
        exit(1);
    }
    
    while(1)
    {
        printf("read:");
        sem_wait(semid,0);

        printf("%s \n",shmaddr);

        sleep(10);

        sem_v(semid,0);
        sleep(10);
    }

    exit(0);
}

你可能感兴趣的:(Linux,linux,信号,共享内存,信号量)