• 进程间的通信


    学习笔记(四)之进程之间的通信

    进程间通信7种:

    一.unix同寿的老三件:
    管道:是一种半双工机制,在unix中大小为64k,存在于内核

    1.无名管道:只能用于有亲缘关系的进程之间,本质通过文件描述符操作
    pipe
    int pipe(int pipefd[2]);
    功能:在内核创建无名管道,并返回操作该管道的两个文件描述符
    参数:1.文件描述符数组 (创建同类型数组,将数组首地址填入) fd[0]得到的是管道的读端 fd[1]得到的是管道的写端
    返回值:成功返回0,失败返回-1,并设置errno号
    注:
    文件描述符不用的及时关闭:
    1.文件描述符是有限的资源
    2.操作不该使用的文件描述符有可能会导致误操作

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <stdlib.h>
     4 #include <strings.h>
     5 #include <string.h>
     6 
     7 int main(int argc, const char *argv[])
     8 {
     9     pid_t pid;
    10 
    11     int ret = 0;
    12     int fd[2];
    13     ret = pipe(fd);
    14     if(ret < 0)
    15     {
    16         perror("fail to pipe");
    17         exit(1);
    18     }
    19 
    20     pid = fork();
    21     if(pid < 0)
    22     {
    23         perror("fail to fork");
    24         exit(1);
    25     }
    26     else if(pid == 0)   //子   fd[1]
    27     {
    28         close(fd[0]);//不操作读端,关闭文件描述符fd[0]
    29         char buf[20];
    30         bzero(buf,sizeof(buf));
    31         fgets(buf,sizeof(buf),stdin);
    32         write(fd[1],buf,strlen(buf));
    33 
    34         exit(0);
    35     }
    36     else  //父  fd[0]
    37     {
    38         sleep(5);
    39         close(fd[1]);//不操作写端,关闭fd[1];
    40         char recv[20];
    41         bzero(recv,sizeof(recv));
    42         read(fd[0],recv,sizeof(recv));
    43         printf("recv:%s\n",recv);
    44         wait(NULL);
    45     }
    46 
    47 
    48     return 0;
    49 }
    pipe

    2.有名管道: 利用文件系统实现两个进程找到内核中的管道(挂载了一个节点)
    mkfifo:
    int mkfifo(const char *pathname, mode_t mode);
    功能:创建有名管道文件
    参数:1.创建管道文件所在路径 2.权限 0666 实际真实权限:(mode & ~umask)
    返回值:成功返回0,失败返回-1,并设置errno号
    EEXIST:测试指定路径下的文件是否已存在,存在报该错误,容错时排除

    注:
    1.操作时读端必须先打开,防止出现错误管道破裂!!!
    2.创建的有名管道文件类型是p,且无大小(在ROM上没有被存放),禁止使用lseek进行操作

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/stat.h>
     4 #include <errno.h>
     5 #include <stdlib.h>
     6 #include <fcntl.h>
     7 #include <strings.h>
     8 
     9 
    10 int main(int argc, const char *argv[])
    11 {
    12     //创建管道文件:
    13     if(-1 == mkfifo("/home/xyx/myfifo",0666))
    14     {
    15         if(errno != EEXIST)
    16         {
    17             perror("fail to mkfifo");
    18             exit(1);
    19         }
    20     }
    21 
    22     int fd;
    23     //以读方式打开管道文件
    24     fd = open("/home/xyx/myfifo",O_RDONLY);
    25     if(fd == -1)
    26     {
    27         perror("fail to open");
    28         exit(1);
    29     }
    30 
    31     char buf[128];
    32 
    33     while(1)
    34     {
    35         bzero(buf,sizeof(buf));
    36         read(fd,buf,sizeof(buf));
    37         printf("recv:%s\n",buf);
    38         if(strncmp(buf,"quit",4) == 0)
    39             exit(0);
    40     }
    41 
    42 
    43     return 0;
    44 }
    fifo_read
     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/stat.h>
     4 #include <errno.h>
     5 #include <stdlib.h>
     6 #include <fcntl.h>
     7 #include <strings.h>
     8 #include <string.h>
     9 
    10 
    11 int main(int argc, const char *argv[])
    12 {
    13     //创建管道文件:由于读端先打开,所以读端先创建管道,该代码可以在写端不写
    14     if(-1 == mkfifo("/home/xyx/myfifo",0666))
    15     {
    16         if(errno != EEXIST)
    17         {
    18             perror("fail to mkfifo");
    19             exit(1);
    20         }
    21     }
    22 
    23     int fd;
    24     //以写方式打开管道文件
    25     fd = open("/home/xyx/myfifo",O_WRONLY);
    26     if(fd == -1)
    27     {
    28         perror("fail to open");
    29         exit(1);
    30     }
    31 
    32     char buf[128];
    33 
    34     while(1)
    35     {
    36         bzero(buf,sizeof(buf));
    37         fgets(buf,sizeof(buf),stdin);
    38         
    39         //删除fgets中的'\n'
    40         if(buf[strlen(buf)-1] == '\n')    
    41             buf[strlen(buf)-1] = '\0';
    42 
    43         write(fd,buf,strlen(buf));//真实数据的长度
    44         if(strncmp(buf,"quit",4) == 0)
    45             exit(0);
    46     }
    47 
    48 
    49     return 0;
    50 }
    fifo_write

    3.信号:
    1.由内核发送给进程
    2.是一种异步机制,是一种软中断

    kill命令:给进程发送指定信号
    kill -l查看信号
    可靠信号: 后面的新的信号
    不可靠信号: 前面的旧的信号
    注:大部分的信号都是杀死进程

    当进程接受到信号时的处理手段:
    1.默认处理 ctrl+c SIGINT 2 ctrl+z SIGSTOP 19
    2.被忽略 SIG_IGN
    3.被捕获 signal
    注:9,19不能忽略和捕获

    kill函数:给进程发送指定信号
    int kill(pid_t pid, int sig);
    参数:1.指定进程pid 2.信号编号
    返回值:成功返回0,失败返回-1,并设置errno号
    对比kill命令:kill -signum pid

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <stdlib.h>
     4 #include <sys/types.h>
     5 #include <signal.h>
     6 
     7 
     8 
     9 int main(int argc, const char *argv[])
    10 {
    11     pid_t pid;
    12 
    13 
    14     pid = fork();
    15     if(pid < 0)
    16     {
    17         perror("fail to fork");
    18         exit(1);
    19     }
    20     else if(pid == 0)
    21     {
    22         while(1)
    23         {
    24             printf("i'm child!\n");
    25             sleep(1);
    26         }
    27 
    28         exit(0);
    29     }
    30     else
    31     {
    32         sleep(5);
    33         kill(pid,SIGKILL);
    34         wait(NULL);
    35         exit(0);
    36     }
    37     return 0;
    38 }
    kill

    raise:给当前调用进程发送信号
    int raise(int sig);
    参数:1.信号编号
    返回值:成功返回0,失败返回非0值
    kill(getpid(),sig) == raise(sig)

     1 #include <stdio.h>
     2 #include <signal.h>
     3 #include <sys/types.h>
     4 #include <unistd.h>
     5 
     6 
     7 
     8 
     9 
    10 int main(int argc, const char *argv[])
    11 {
    12     sleep(2);
    13 
    14     kill(getpid(),SIGKILL);
    15 //    raise(SIGKILL);
    16     return 0;
    17 }
    raise

    alarm:指定时间后发送SIGALRM的信号给当前进程 (自爆闹钟)
    unsigned int alarm(unsigned int seconds);
    参数:1.秒数 通常情况下不填0

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 
     4 
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     alarm(10);
     9 
    10 
    11     while(1)
    12     {
    13         printf("11111111\n");
    14         sleep(1);
    15     }
    16     return 0;
    17 }
    alarm

    pause:阻塞进程直到进程收到任意信号
    int pause(void);

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <sys/types.h>
     4 
     5 
     6 
     7 
     8 int main(int argc, const char *argv[])
     9 {
    10     printf("111111\n");
    11     printf("getpid:%d\n",getpid());
    12     pause();
    13 
    14     printf("222222\n");
    15     return 0;
    16 }
    pause

    signal
    sighandler_t signal(int signum, sighandler_t handler);
    参数:1.信号编号 2.函数指针 信号处理函数的入口地址 void 函数名(int(信号编号))
    typedef void (*sighandler_t)(int);
    void(*)(int) == sighandler_t 本质就是函数指针
    功能:向内核注册对应信号,当当前进程收到该信号时,不会执行信号的默认操作,直接捕获信号
    执行对应的信号处理函数(官方提供信号处理宏函数SIG_IGN(被忽略) SIG_DFL)
    返回值:不关心
    注:SIGKILL SIGSTOP无法被signal捕获和忽略

     1 #include <stdio.h>
     2 #include <signal.h>
     3 #include <unistd.h>
     4 #include <sys/types.h>
     5 
     6 //信号处理函数
     7 void handler(int signum)
     8 {
     9     if(signum == SIGQUIT)
    10     {
    11         printf("ctrl + \\ is used!\n");
    12     }
    13     else if(signum == SIGINT)
    14     {
    15         printf("ctrl + c is used!\n");
    16     }
    17     else if(signum == SIGALRM)
    18     {
    19         printf("alarm is used!\n");
    20     }
    21     else  
    22     {
    23         printf("SIGKILL is used!\n");
    24     }
    25 }
    26 
    27 int main(int argc, const char *argv[])
    28 {
    29     printf("getpid:%d\n",getpid());    
    30     signal(SIGINT,handler);
    31     signal(SIGKILL,handler);//无法被捕获
    32     signal(SIGALRM,handler);
    33     signal(SIGQUIT,handler);//ctrl+\
    34 
    35     alarm(5);
    36 
    37      while(1)
    38      {
    39          sleep(1);
    40          printf("i'm alive no one can kill me !\n");
    41      }
    42 
    43 
    44     return 0;
    45 }
    signal

    二.IPC三件套: system V 的 IPC 贝尔实验室
    ftok:令牌函数 让多个进程找到同一个事件(同一块地方)
    key_t ftok(const char *pathname, int proj_id);
    参数:1.已知或已存在的文件路径(借助该文件的inode) 2.随意的一个整形数值,保证需要沟通的进程数值一致
    返回值:成功返回计算的key值,失败返回-1,并设置errno号

    消息队列: 内核泛型链表 关键字链式队列
    msgget:创建消息队列
    int msgget(key_t key, int msgflg);
    参数:1.key值 2.权限 创建时:IPC_CREAT | IPC_EXCL | 0666
    访问时:0666
    返回值:成功时返回消息队列编号msgid 失败返回-1,并设置errno号
    errno号为EEXIST时代表消息队列存在,容错时注意,直接访问消息队列即可

    ipcs -q:查询消息队列

    msgsnd 插入数据
    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    参数:1.msgid 2.插入数据的类型 必须以如下结构体形式书写
    struct msgbuf {
    long mtype; /* message type, must be > 0 */ 数据类型用于区分数据 >0
    char mtext[1]; /* message data */ 正文内容
    };
    3.正文长度 sizeof(msgbuf) - sizeof(long) 4.填0默认阻塞等待数据写入 (IPC_NOWAIT非阻塞)
    返回值:失败返回-1,并设置errno号,成功返回0

    msgrcv 接收数据
    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
    参数:1.msgid 2.接收数据的类型 (自己创建空间接收) 3.正文长度 4.>0 接收指定数据类型的消息=0 默认接受消息队列中第一个成员的数据
    5.填0默认阻塞
    返回值:失败返回-1,并设置errno号,成功返回0

    msgctl
    int msgctl(int msqid, int cmd, struct msqid_ds *buf);
    参数:1.msgid 2.指令 删除时用IPC_RMID 3.删除时填NULL即可
    返回值:失败返回-1,并设置errno号

    注:消息队列一般写书写recv端 启动时先打开recv端 创建消息队列和删除消息队列都是recv操作

    命令删除:ipcrm -q msgid

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/msg.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <strings.h>
     8 #include <string.h>
     9 //插入数据的类型
    10 typedef struct node
    11 {
    12     long type;
    13     char buf[128];
    14 }msg_t;
    15 
    16 int main(int argc, const char *argv[])
    17 {
    18     //ftok   计算key值
    19     key_t key;
    20     key = ftok("/home/xyx/123.c",'a');
    21     if(key == -1)
    22     {
    23         perror("fail to ftok");
    24         exit(1);
    25     }
    26 
    27     //msgget 创建链表
    28     int msgid;
    29     msgid = msgget(key,IPC_CREAT | IPC_EXCL | 0666);
    30     if(msgid == -1)
    31     {
    32         if(errno == EEXIST)
    33         {
    34             //消息队列存在直接访问
    35             msgid = msgget(key,0666);
    36         }
    37         else
    38         {
    39             perror("fail to msgget");
    40             exit(1);
    41         }
    42     }
    43 
    44     //创建后检验消息队列
    45     system("ipcs -q");
    46 
    47     //用于接收数据的空间
    48     msg_t *recv;
    49     recv = malloc(sizeof(msg_t));
    50 
    51 
    52     while(1)
    53     {
    54 
    55         bzero(recv,sizeof(msg_t));
    56 
    57         //接收数据 msgrcv
    58         if(-1 == msgrcv(msgid,recv,sizeof(msg_t)-sizeof(long),100,0))
    59         {
    60             perror("fail to msgrcv");
    61             exit(1);
    62         }
    63 
    64         printf("recv:%s\n",recv->buf);
    65 
    66         if(strncmp(recv->buf,"quit",4) == 0)
    67             break;
    68 
    69 
    70     }
    71     //删除消息队列 msgctl
    72     msgctl(msgid,IPC_RMID,NULL);
    73 
    74     //检查是否成功删除
    75     system("ipcs -q");
    76 
    77     free(recv);
    78 
    79     return 0;
    80 }
    msg_recv
     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/msg.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <strings.h>
     8 #include <string.h>
     9 //插入数据的类型
    10 typedef struct node
    11 {
    12     long type;
    13     char buf[128];
    14 }msg_t;
    15 
    16 int main(int argc, const char *argv[])
    17 {
    18     //ftok   计算key值
    19     key_t key;
    20     key = ftok("/home/xyx/123.c",'a');
    21     if(key == -1)
    22     {
    23         perror("fail to ftok");
    24         exit(1);
    25     }
    26 
    27     //msgget 创建链表
    28     int msgid;
    29     msgid = msgget(key,IPC_CREAT | IPC_EXCL | 0666);
    30     if(msgid == -1)
    31     {
    32         if(errno == EEXIST)
    33         {
    34             //消息队列存在直接访问
    35             msgid = msgget(key,0666);
    36         }
    37         else
    38         {
    39             perror("fail to msgget");
    40             exit(1);
    41         }
    42     }
    43 
    44     //创建后检验消息队列
    45     system("ipcs -q");
    46 
    47     //开辟空间用于发送数据
    48     msg_t *send;
    49     send = malloc(sizeof(msg_t));
    50 
    51 
    52     while(1)
    53     {
    54         //清空
    55         bzero(send,sizeof(msg_t));
    56 
    57         //写入数据
    58         send->type = 100; //标记消息类型为100 必须>0
    59         fgets(send->buf,sizeof(send->buf),stdin);//填入数据
    60 
    61         //插入数据 msgsnd        
    62         if(-1 == msgsnd(msgid,send,sizeof(msg_t)-sizeof(long),0))
    63         {
    64             perror("fail to msgsnd");
    65             exit(1);
    66         }
    67 
    68         if(strncmp(send->buf,"quit",4) == 0)
    69             break;
    70 
    71     }    
    72 
    73     free(send);
    74     return 0;
    75 }
    msg_send

    共享内存:真实物理内存 关键字映射
    ftok
    ipcs -m 查询共享内存
    ipcrm -m 共享内存号 命令删除共享内存

    shmget:申请空间
    int shmget(key_t key, size_t size, int shmflg);
    参数:1.key 2.申请空间的大小 3.权限 创建时:IPC_CREAT | IPC_EXCL | 0666
    访问时:0666
    返回值:成功返回shmid 失败返回-1,并设置errno号
    errno号为EEXIST时代表共享内存存在,容错时注意,直接访问共享内存即可

    shmat:映射
    void *shmat(int shmid, const void *shmaddr, int shmflg);
    参数:1.shmid 2.映射的虚拟地址 填NULL自动分配 3.权限 填0表示读写均可以 填SHM_RDONLY代表只读
    返回值:成功返回映射的虚拟空间的首地址 失败返回(void *)-1 并设置errno号

    shmdt:取消映射
    int shmdt(const void *shmaddr);
    参数:1.映射成功后返回的首地址

    shmctl
    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    参数:1.shmid 2.指令 IPC_RMID删除指令 3.删除时填NULL即可

    实现共享内存同步方式:
    注:recv先开后关 初始化以及shmget以及shmctl均由recv操作 send循环使用时注意清空共享内存
    1.flag flag在结构体中,放在共享内存中实现

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/shm.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <string.h>
     8 //自己约定的传输数据格式
     9 typedef struct a
    10 {
    11     int led1;
    12     int led2;
    13     char buf[128];
    14 }node_t;
    15 
    16 int main(int argc, const char *argv[])
    17 {
    18     //ftok 计算key值
    19     key_t key;
    20     
    21     key = ftok("/home/xyx/123.c",'b');
    22     if(key == -1)
    23     {
    24         perror("fail to ftok");
    25         exit(1);
    26     }
    27 
    28     //创建共享内存 shmget
    29     int shmid;
    30     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
    31     if(shmid == -1)
    32     {
    33         if(errno == EEXIST)
    34         {
    35             shmid = shmget(key,sizeof(node_t),0666);
    36         }
    37         else
    38         {
    39             perror("fail to shmget");
    40             exit(0);
    41         }
    42     }
    43     
    44     //检查共享内存是否创建成功
    45     system("ipcs -m");
    46 
    47     //映射 shmat
    48     node_t *addr;
    49     addr = shmat(shmid,NULL,0);
    50     if(addr == (void *)-1)
    51     {
    52         perror("fail to shmat");
    53         exit(1);
    54     }
    55     
    56     //do somthing
    57     //初始化  led1 send  led2 recv
    58     addr->led1 = 1;
    59     addr->led2 = 0;
    60         
    61     while(1)
    62     {
    63         if(addr->led2 == 1)
    64         {
    65             printf("recv:%s\n",addr->buf);
    66             addr->led2--;
    67             addr->led1++;
    68             if(strncmp(addr->buf,"quit",4) == 0)
    69                 break;
    70         }
    71     }
    72 
    73     //取消映射 shmdt
    74     shmdt(addr);
    75 
    76     
    77     //销毁空间 shmctl
    78     shmctl(shmid,IPC_RMID,NULL);
    79 
    80     system("ipcs -m");
    81 
    82     return 0;
    83 }
    flag_recv
     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/shm.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <string.h>
     8 //自己约定的传输数据格式
     9 typedef struct a
    10 {
    11     int led1;
    12     int led2;
    13     char buf[128];
    14 }node_t;
    15 
    16 int main(int argc, const char *argv[])
    17 {
    18     //ftok 计算key值
    19     key_t key;
    20     
    21     key = ftok("/home/xyx/123.c",'b');
    22     if(key == -1)
    23     {
    24         perror("fail to ftok");
    25         exit(1);
    26     }
    27 
    28     //创建共享内存 shmget
    29     int shmid;
    30     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
    31     if(shmid == -1)
    32     {
    33         if(errno == EEXIST)
    34         {
    35             shmid = shmget(key,sizeof(node_t),0666);
    36         }
    37         else
    38         {
    39             perror("fail to shmget");
    40             exit(0);
    41         }
    42     }
    43     
    44     //检查共享内存是否创建成功
    45     system("ipcs -m");
    46 
    47     //映射 shmat
    48     node_t *addr;
    49     addr = shmat(shmid,NULL,0);
    50     if(addr == (void *)-1)
    51     {
    52         perror("fail to shmat");
    53         exit(1);
    54     }
    55     
    56     //do somthing
    57     while(1)
    58     {
    59         if(addr->led1 == 1)
    60         {
    61             memset(addr->buf,0,128);
    62             fgets(addr->buf,sizeof(addr->buf),stdin);
    63 
    64             addr->led1--;
    65             addr->led2++;
    66 
    67             if(strncmp(addr->buf,"quit",4) == 0)
    68                 break;
    69         }
    70     }
    71     
    72 
    73     //取消映射 shmdt
    74     shmdt(addr);
    75 
    76 
    77     return 0;
    78 }
    flag_send

    2.信号

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/shm.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <unistd.h>
     8 #include <signal.h>
     9 #include <string.h>
    10 //自己约定的传输数据格式
    11 typedef struct a
    12 {
    13     pid_t pid_send;
    14     pid_t pid_recv;
    15     char buf[128];
    16 }node_t;
    17 
    18 //信号处理函数
    19 void handler(int signum)   
    20 {
    21     ;
    22 }
    23 
    24 int main(int argc, const char *argv[])
    25 {
    26     //ftok 计算key值
    27     key_t key;
    28 
    29     key = ftok("/home/xyx/123.c",'b');
    30     if(key == -1)
    31     {
    32         perror("fail to ftok");
    33         exit(1);
    34     }
    35 
    36     //创建共享内存 shmget
    37     int shmid;
    38     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
    39     if(shmid == -1)
    40     {
    41         if(errno == EEXIST)
    42         {
    43             shmid = shmget(key,sizeof(node_t),0666);
    44         }
    45         else
    46         {
    47             perror("fail to shmget");
    48             exit(0);
    49         }
    50     }
    51 
    52     //检查共享内存是否创建成功
    53     system("ipcs -m");
    54 
    55     //映射 shmat
    56     node_t *addr;
    57     addr = shmat(shmid,NULL,0);
    58     if(addr == (void *)-1)
    59     {
    60         perror("fail to shmat");
    61         exit(1);
    62     }
    63 
    64     //do somthing
    65     addr->pid_recv = getpid();
    66 
    67     //SIGUSR1 recv->send      SIGUSR2 send->recv
    68     signal(SIGUSR2,handler);  //捕获信号,不做任何操作
    69 
    70 
    71     while(1)
    72     {
    73         pause(); //阻塞等待
    74         printf("recv:%s\n",addr->buf);
    75 
    76         if(strncmp(addr->buf,"quit",4) == 0)
    77             break;
    78 
    79         kill(addr->pid_send,SIGUSR1);
    80     }
    81 
    82     //取消映射 shmdt
    83     shmdt(addr);
    84 
    85 
    86     //销毁空间 shmctl
    87     shmctl(shmid,IPC_RMID,NULL);
    88 
    89     system("ipcs -m");
    90 
    91     return 0;
    92 }
    signal_recv
     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/shm.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <unistd.h>
     8 #include <string.h>
     9 #include <signal.h>
    10 //自己约定的传输数据格式
    11 typedef struct a
    12 {
    13     pid_t pid_send;
    14     pid_t pid_recv;
    15     char buf[128];
    16 }node_t;
    17 
    18 void handler(int signum)
    19 {
    20     ;
    21 }
    22 
    23 
    24 int main(int argc, const char *argv[])
    25 {
    26     //ftok 计算key值
    27     key_t key;
    28     
    29     key = ftok("/home/xyx/123.c",'b');
    30     if(key == -1)
    31     {
    32         perror("fail to ftok");
    33         exit(1);
    34     }
    35 
    36     //创建共享内存 shmget
    37     int shmid;
    38     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
    39     if(shmid == -1)
    40     {
    41         if(errno == EEXIST)
    42         {
    43             shmid = shmget(key,sizeof(node_t),0666);
    44         }
    45         else
    46         {
    47             perror("fail to shmget");
    48             exit(0);
    49         }
    50     }
    51     
    52     //检查共享内存是否创建成功
    53     system("ipcs -m");
    54 
    55     //映射 shmat
    56     node_t *addr;
    57     addr = shmat(shmid,NULL,0);
    58     if(addr == (void *)-1)
    59     {
    60         perror("fail to shmat");
    61         exit(1);
    62     }
    63     
    64     //do somthing
    65     addr->pid_send = getpid();
    66 
    67     signal(SIGUSR1,handler);
    68     
    69     while(1)
    70     {
    71         memset(addr->buf,0,sizeof(addr->buf));
    72 
    73         fgets(addr->buf,sizeof(addr->buf),stdin);
    74 
    75         kill(addr->pid_recv,SIGUSR2);
    76 
    77         if(strncmp(addr->buf,"quit",4) == 0)
    78             break;
    79 
    80         pause();
    81     }
    82 
    83     //取消映射 shmdt
    84     shmdt(addr);
    85 
    86     return 0;
    87 }
    signal_send

    3.信号灯集

    信号灯集: 瞬间操作多盏信号灯,信号量的集合
    ftok
    ipcs -s
    ipcrm -s semid

    semget :创建信号灯集
    int semget(key_t key, int nsems, int semflg);
    参数:1.key 2.信号灯的数量 3.权限 创建时:IPC_CREAT | IPC_EXCL | 0666
    访问时:0666
    返回值:成功执行返回semid,失败返回-1,并设置errno号
    errno号为EEXIST时代表信号灯集存在,容错时注意,直接访问信号灯集即可

    semctl: 初始化操作 相当于线程中sem_init
    int semctl(int semid, int semnum, int cmd, ...);
    参数:1.semid 2.指定的灯号 3.指令 SETVAL对指定灯初始化
    4.可选参数,根据参数3决定是否使用,使用时必须定义如下联合体
    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) */
    };

    semop: pv操作 相当于线程中sem_post sem_wait
    int semop(int semid, struct sembuf *sops, unsigned nsops);
    参数:1.semid 2.p,v操作的结构体,类型如下
    unsigned short sem_num; /* semaphore number */ 信号量的编号
    short sem_op; /* semaphore operation */ p,v操作 +1 -1
    short sem_flg; /* operation flags */ 使用SEM_UNDO
    3.一次性操作的灯数
    返回值:成功返回0,失败返回-1,并设置errno号

    semctl:销毁信号灯集
    int semctl(int semid, int semnum, int cmd, ...);
    参数:1.semid 2.使用IPC_RMID时忽略改参数 填0 3.删除使用IPC_RMID 4.不使用

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <stdlib.h>
     5 #include <sys/sem.h>
     6 #include <errno.h>
     7 
     8 typedef struct a
     9 {
    10     char buf[128];
    11 }node_t;
    12 
    13 
    14 //封装semctl 实现sem_init
    15 int mysem_init(int semid,int n,int value)
    16 { 
    17     union semun {
    18         int        val;    /* Value for SETVAL */
    19         struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    20         unsigned short  *array;    /* Array for GETALL, SETALL */
    21         struct seminfo  *__buf;    /* Buffer for IPC_INFO
    22                                    (Linux-specific) */
    23     };
    24 
    25     union semun buf;
    26     buf.val = value;
    27     if(-1 == semctl(semid,n,SETVAL,buf))
    28     {
    29         perror("fail to semctl");
    30         exit(1);
    31     }
    32 
    33     return 0;
    34 }
    35 
    36 //封装semop 实现sem_post sem_wait
    37 int mysem_post(int semid,int n)
    38 {
    39     struct sembuf buf;
    40     buf.sem_num = n;
    41     buf.sem_op = 1;
    42     buf.sem_flg = SEM_UNDO;
    43 
    44     if(-1 == semop(semid,&buf,1))
    45     {
    46         perror("fail to semop");
    47         exit(1);
    48     }
    49 
    50     return 0;
    51 }
    52 
    53 
    54 int mysem_wait(int semid,int n)    
    55 {
    56     struct sembuf buf;
    57     buf.sem_num = n;
    58     buf.sem_op = -1;
    59     buf.sem_flg = SEM_UNDO;
    60 
    61     if(-1 == semop(semid,&buf,1))
    62     {
    63         perror("fail to semop");
    64         exit(1);
    65     }
    66 
    67     return 0;
    68 }
    sem_h
     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/shm.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <string.h>
     8 #include <sys/sem.h>
     9 
    10 #include "shm_sem.h"
    11 
    12 int main(int argc, const char *argv[])
    13 {
    14     //ftok 计算key值
    15     key_t key;
    16     
    17     key = ftok("/home/xyx/123.c",'b');
    18     if(key == -1)
    19     {
    20         perror("fail to ftok");
    21         exit(1);
    22     }
    23 
    24     //创建共享内存 shmget
    25     int shmid;
    26     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
    27     if(shmid == -1)
    28     {
    29         if(errno == EEXIST)
    30         {
    31             shmid = shmget(key,sizeof(node_t),0666);
    32         }
    33         else
    34         {
    35             perror("fail to shmget");
    36             exit(0);
    37         }
    38     }
    39     
    40     //创建信号灯集
    41     int semid;
    42     semid = semget(key,2,IPC_CREAT | IPC_EXCL | 0666);
    43     if(semid == -1)
    44     {
    45         if(errno == EEXIST)
    46         {
    47             semid = semget(key,2,0666);
    48         }
    49         else
    50         {
    51             perror("fail to semget");
    52             exit(1);
    53         }
    54     }
    55 
    56     //检查共享内存和信号灯集是否创建成功
    57     system("ipcs -m");
    58     system("ipcs -s");
    59     
    60     //映射 shmat
    61     node_t *addr;
    62     addr = shmat(shmid,NULL,0);
    63     if(addr == (void *)-1)
    64     {
    65         perror("fail to shmat");
    66         exit(1);
    67     }
    68     
    69     //do somthing
    70     //初始化
    71     mysem_init(semid,0,1);  //0灯给send
    72     mysem_init(semid,1,0);  //1灯给recv
    73     
    74     while(1)
    75     {
    76         mysem_wait(semid,1);//1灯-1
    77         printf("recv:%s\n",addr->buf);
    78 
    79         if(strncmp(addr->buf,"quit",4) == 0)
    80             break;
    81 
    82         mysem_post(semid,0);//0灯+1
    83     }
    84 
    85     //取消映射 shmdt
    86     shmdt(addr);
    87 
    88     
    89     //销毁空间 shmctl
    90     shmctl(shmid,IPC_RMID,NULL);
    91 
    92     //销毁信号灯集 
    93     semctl(semid,0,IPC_RMID);
    94 
    95 
    96     system("ipcs -m");
    97     system("ipcs -s");
    98     return 0;
    99 }
    sem_recv
     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/ipc.h>
     4 #include <sys/shm.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <string.h>
     8 #include <sys/sem.h>
     9 
    10 #include "shm_sem.h"
    11 
    12 int main(int argc, const char *argv[])
    13 {
    14     //ftok 计算key值
    15     key_t key;
    16     
    17     key = ftok("/home/xyx/123.c",'b');
    18     if(key == -1)
    19     {
    20         perror("fail to ftok");
    21         exit(1);
    22     }
    23 
    24     //创建共享内存 shmget
    25     int shmid;
    26     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
    27     if(shmid == -1)
    28     {
    29         if(errno == EEXIST)
    30         {
    31             shmid = shmget(key,sizeof(node_t),0666);
    32         }
    33         else
    34         {
    35             perror("fail to shmget");
    36             exit(0);
    37         }
    38     }
    39     
    40     //创建信号灯集
    41     int semid;
    42     semid = semget(key,2,IPC_CREAT | IPC_EXCL | 0666);
    43     if(semid == -1)
    44     {
    45         if(errno == EEXIST)
    46         {
    47             semid = semget(key,2,0666);
    48         }
    49         else
    50         {
    51             perror("fail to semget");
    52             exit(1);
    53         }
    54     }
    55 
    56     //检查共享内存和信号灯集是否创建成功
    57     system("ipcs -m");
    58     system("ipcs -s");
    59     
    60     //映射 shmat
    61     node_t *addr;
    62     addr = shmat(shmid,NULL,0);
    63     if(addr == (void *)-1)
    64     {
    65         perror("fail to shmat");
    66         exit(1);
    67     }
    68     
    69     //do somthing
    70     //初始化
    71     mysem_init(semid,0,1);  //0灯给send
    72     mysem_init(semid,1,0);  //1灯给recv
    73     
    74     while(1)
    75     {
    76         mysem_wait(semid,1);//1灯-1
    77         printf("recv:%s\n",addr->buf);
    78 
    79         if(strncmp(addr->buf,"quit",4) == 0)
    80             break;
    81 
    82         mysem_post(semid,0);//0灯+1
    83     }
    84 
    85     //取消映射 shmdt
    86     shmdt(addr);
    87 
    88     
    89     //销毁空间 shmctl
    90     shmctl(shmid,IPC_RMID,NULL);
    91 
    92     //销毁信号灯集 
    93     semctl(semid,0,IPC_RMID);
    94 
    95 
    96     system("ipcs -m");
    97     system("ipcs -s");
    98     return 0;
    99 }
    sem_send

    socket一打六,

  • 相关阅读:
    Android 对话框(Dialog)
    struts2 开发模式
    Struts2动态方法调用(DMI)
    Struts2中 Path (getContextPath与basePath)
    String path = request.getContextPath
    ios虚拟机安装(二)
    Spring MVC 的 研发之路
    Swift辛格尔顿设计模式(SINGLETON)
    【算法导论】多项式求和
    uva 11181
  • 原文地址:https://www.cnblogs.com/hslixiqian/p/9559480.html
Copyright © 2020-2023  润新知