linux进程间通信方式--学习笔迹3

5 篇文章 0 订阅

进程间通信的方式

进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。
IPC的方式通常有管道(包括无名管道和命名管道)
消息队列
信号量
共享存储
Socket、Streams等。
其中 Socket和Streams支持不同主机上的两个进程IPC。

1管道

无名管道形式:

   #include <unistd.h>

   int pipe(int pipefd[2]);

例子

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

int main()
{
        int fd[2];
        int pid;
        char buf[128];
        int status;
        if(pipe(fd)==-1)
        {
                printf("creat pipe error\n");
        }
        pid =fork();
        if(pid<0)
        {

                printf("creat chuld failed\n");
        }
        else if(pid>0)
        {
            sleep(3);
            printf("this is father\n");
            close(fd[0]);
            write(fd[1],"hello",strlen("hell0"));
            wait(&status);
        }
        else
        {
                printf("this is child\n");
                close(fd[1]);
                read(fd[0],buf,128);
                printf("read from father:%s\n",buf);
                exit(0);
        }
        return 0;
}

2、有名管道

有名管道形式:

 #include <sys/stat.h>
 // 返回值:成功返回0,出错返回-1
 int mkfifo(const char *pathname, mode_t mode);

mode 参数与open函数中的 mode 相同。一旦创建了一个 FIFO,就可以用一般的文件I/O函数操作它。
若没有指定O_NONBLOCK(默认),只读 open 要阻塞到某个其他进程为写而打开此 FIFO。
例子:
write:

#include "stdio.h"
#include "unistd.h"
#include "string.h"
#include "stdlib.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include "fcntl.h"
int main()
{
        char *str ="message from fifo";
        int fd =open("./file1",O_WRONLY);
        printf("open succes");
        while(1)
        {
                write(fd,str,strlen(str));
                sleep(1);
                printf("send a message");
        }
        close(fd);
        return 0;
}

read:

#include "stdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include "fcntl.h"
#include "errno.h"
#include "unistd.h"
int main()
{
        char buf[30]={0};
        int n_read=0;
        if((mkfifo("./file1",0600)==-1) && errno!=EEXIST)
        {
                printf("mkfifo failure\n");
                perror("why");
        }
        int fd =open("./file1",O_RDONLY);
        printf("open succes\n");
        while(1)
        {
        n_read=read(fd,buf,30);
        printf("read %d byte from fifo,context:%s\n",n_read,buf);
        }
        close(fd);
        return 0;
}

3、消息队列

消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
ftok函数将文件名转化为键值
形式:

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

       key_t ftok(const char *pathname, int proj_id);
 #include <sys/msg.h>
 // 创建或打开消息队列:成功返回队列ID,失败返回-1
 int msgget(key_t key, int flag);
 // 添加消息:成功返回0,失败返回-1
 int msgsnd(int msqid, const void *ptr, size_t size, int flag);
 // 读取消息:成功返回消息数据的长度,失败返回-1
 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
 // 控制消息队列:成功返回0,失败返回-1
 int msgctl(int msqid, int cmd, struct msqid_ds *buf);

例子
send:

#include"stdio.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "string.h"
struct msgbuf {
     long mtype;       /* message type, must be > 0 */
     char mtext[128];    /* message data */
};
int main()
{
        struct msgbuf sendBuf={888,"this is massage from que"};
        struct msgbuf readBuf;
        key_t key;
        key=ftok(".",'z');
        printf("key:%x\n",key);
        int msgid=msgget(key,IPC_CREAT|0777);
        if(msgid==-1)
        {
                printf("get que failure\n");
        }
        msgsnd(msgid,&sendBuf,sizeof(sendBuf.mtext),0);
        printf("send over");
        msgrcv(msgid,&readBuf,sizeof(readBuf.mtext),988,0);
        printf("reach from get :%s\n",readBuf.mtext);
        msgctl(msgid,IPC_RMID,NULL);
        return 0;
}

get:

#include"stdio.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "string.h"
struct msgbuf {
     long mtype;       /* message type, must be > 0 */
     char mtext[128];    /* message data */
};
int main()
{
        struct msgbuf readBuf;
        key_t key;
        key=ftok(".",'z');
        printf("key:%x\n",key);
        int msgid=msgget(key,IPC_CREAT|0777);

        if(msgid==-1)
        {
                printf("get que failure\n");
        }
        msgrcv(msgid,&readBuf,sizeof(readBuf.mtext),888,0);
        printf("read from que:%s\n",readBuf.mtext);
        struct msgbuf sendBuf={988,"thank you for reach"};
        msgsnd(msgid,&sendBuf,strlen(sendBuf.mtext),0);
        msgctl(msgid,IPC_RMID,NULL);
        return 0;
}

4、共享内存

共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。
函数形式:

 #include <sys/shm.h>
 // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
 int shmget(key_t key, size_t size, int flag);
 // 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
 void *shmat(int shm_id, const void *addr, int flag);
 // 断开与共享内存的连接:成功返回0,失败返回-1
 int shmdt(void *addr); 
 // 控制共享内存的相关信息:成功返回0,失败返回-1
 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);

例子
write:

#include <sys/ipc.h>
#include <sys/shm.h>
#include "stdio.h"
#include"string.h"
#include"stdlib.h"
#include "unistd.h"


int main()
{
        int shmid;
        char *shmaddr;
        key_t key;
        key=ftok(".",1);
        shmid=shmget(key,1024*4,IPC_CREAT|0666);
        if(shmid==-1)
        {
                printf("shmget failure\n");
                exit(-1);
        }
        shmaddr=shmat(shmid,0,0);
        printf("shmat ok\n");
        strcpy(shmaddr,"shaoshuai\n");
        sleep(5);
        shmdt(shmaddr);
        shmctl(shmid,IPC_RMID,0);
        printf("Quit\n");
        return 0;
}

read:

#include <sys/ipc.h>
#include <sys/shm.h>
#include "stdio.h"
#include"string.h"
#include"stdlib.h"
#include "unistd.h"


int main()
{
        int shmid;
        char *shmaddr;
        key_t key;
        key=ftok(".",1);
        shmid=shmget(key,1024*4,0);
        if(shmid==-1)
        {
                printf("shmget failure\n");
                exit(-1);
        }
        shmaddr=shmat(shmid,0,0);
        printf("shmat ok\n");
        printf("data:%s",shmaddr);
        shmdt(shmaddr);
        printf("Quit\n");
        return 0;
}

5、信号

类似中断
入门:
kill:发消息
signal:放消息

例子:

#include <signal.h>
#include"stdio.h"
//       typedef void (*sighandler_t)(int);

 //      sighandler_t signal(int signum, sighandler_t handler);
void handler(int signum)
{
        printf("get signum=%d\n",signum);
        switch(signum)
        {
                case 2:
                        printf("SIGINT\n");
                        break;
                case 9:
                        printf("SIGKILL\n");
                        break;
                case 10:
                        printf("SIGUSR1\n");
                        break;
        }
        printf("never Quit\n");
}
int main()
{
        signal(SIGINT,SIG_IGN);
        signal(SIGKILL,SIG_IGN);
        signal(SIGUSR1,handler);
        while(1);
        return 0;
}

#include <signal.h>
#include"stdio.h"
#include <sys/types.h>
#include <signal.h>
#include"stdlib.h"
int main(int argc,char **argv)
{
        int signum;
        int pid;

        signum=atoi(argv[1]);
        pid = atoi(argv[2]);

        printf("num=%d,pid=%d\n",signum,pid);

        kill(pid,signum);
        printf("process killed");

        return 0;
}

高级版:

1 #include <sys/sem.h>
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int num_sems, int sem_flags);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf semoparray[], size_t numops);  
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);

例子

#include <signal.h>
#include"stdio.h"
#include <sys/types.h>
#include <unistd.h>

//       int sigaction(int signum, const struct sigaction *act,
 //                    struct sigaction *oldact);

void handler(int signum, siginfo_t *info, void *context)
{
        printf("get signum %d\n",signum);
        if(context!=NULL)
        {
                printf("get data%d\n",info->si_int);
                printf("get data:%d\n",info->si_value.sival_int);
                printf("from%d",info->si_pid);
        }
}

int main()
{
        struct sigaction act;
        printf("pid=%d\n",getpid());
        act.sa_sigaction=handler;
        act.sa_flags=SA_SIGINFO;//be able to get message


        sigaction(SIGUSR1,&act,NULL);
        while(1);
        return 0;

}
~   
#include"stdio.h"
#include"signal.h"
#include"stdlib.h"
#include <sys/types.h>
#include <unistd.h>

int main(int argc,char **argv)
{
        int signum;
        int pid;
        signum=atoi(argv[1]);
        pid=atoi(argv[2]);
        union sigval value;
        value.sival_int=100;
//int sigqueue(pid_t pid, int sig, const union sigval value);
        sigqueue(pid,signum,value);
        printf("%d,done\n",getpid());
        return 0;
}

信号量

信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
函数形式:

 #include <sys/sem.h>
 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
 int semget(key_t key, int num_sems, int sem_flags);
 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
 int semop(int semid, struct sembuf semoparray[], size_t numops);  
 // 控制信号量的相关信息
 int semctl(int semid, int sem_num, int cmd, ...);

例子:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include"unistd.h"
//int semget(key_t key, int nsems, int semflg);
union semun {
   int              val;    /* Value for SETVAL */
   struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
   unsigned short  *array;  /* Array for GETALL, SETALL */
   struct seminfo  *__buf;  /* Buffer for IPC_INFO
                               (Linux-specific) */
};
void pGetKey(int id)
{
        struct sembuf sops;
        sops.sem_num = 0;        /* Operate on semaphore 0 */
        sops.sem_op = -1;         /* Wait for value to equal 0 */
        sops.sem_flg = SEM_UNDO;
        semop(id,&sops,1);
        printf("get key\n");
}
void pPutBackKey(int id)
{
        struct sembuf sops;
        sops.sem_num = 0;        /* Operate on semaphore 0 */
        sops.sem_op = 1;         /* Wait for value to equal 0 */
        sops.sem_flg = SEM_UNDO;
        semop(id,&sops,1);
        printf("put back the key\n");
}
int main(int argc,int const *argv[])
{
    key_t key;
    int semid;
    key = ftok(".",2);
    semid=semget(key,1,IPC_CREAT|0666);
    union semun initsem;
    initsem.val=0;
    semctl(semid,0,SETVAL,initsem);
    int pid=fork();
    if(pid>0)
    {
        pGetKey(semid);
        printf("this is father\n");
        pPutBackKey(semid);
    }
    else if(pid==0)
    {
        printf("this is child\n");
        pPutBackKey(semid);
    }
    else
    {
        printf("creat failure");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值