Day31、未决信号、有名管道、IPC进程间通讯(消息队列)

来源:互联网 发布:非线性最优化确定参数 编辑:程序博客网 时间:2024/05/01 12:05

补充:

html

apache(web)

C语言写网站后台程序,称作CGI

 

今天:

一、            未决信号

定义:从信号的产生到信号的到达,在这期间叫做未决信号

sigpending(2)

#include <signal.h>

int sigpending(sigset_t *set);

功能:检查未决信号,将信号集里的未决信号的相应位置1

参数:

set:信号集 (值_结果参数)

返回值:

成功返回0,失败返回1

举例:vi pending.c

  1 #include<stdio.h>

  2 #include<signal.h>

  3 int main(){

  4     sigset_t set;

  5     sigset_t pset;

  6     //清空set

  7     sigemptyset(&pset);

  8     sigemptyset(&set);

  9     //将信号添加到集合set里

 10     sigaddset(&set,SIGINT);

 11     //设置信号的屏蔽

 12     sigprocmask(SIG_SETMASK,&set,NULL);

 13     sleep(10);

 14     //获取未决信号

 15     sigpending(&pset);

 16     //判断SIGINT是不是未决信号

 17     if(sigismember(&pset,SIGINT)==1){//一次检测一个,这次检测SIGINT,若要检测其他信号,再写if语句

 18         printf("SIGINTpending...\n");

 19     }

 20     return 0;

 21 }            

tarena@tarena-virtual-machine:~/day31$./a.out

^CSIGINT pending...

作用:在休眠10s内输入ctrl+c,没有反应(阻塞),最后判断SIGINT是不是未决信号

输入ctrl+c产生了信号,但是被sigprocmask设置屏蔽,此时的信号就是未决信号

改变:

  1#include<stdio.h>

  2#include<signal.h>

  3int main(){

 4     sigset_t set;

 5     sigset_t pset;

 6     //清空set

 7     sigemptyset(&pset);

 8     sigemptyset(&set);

 9     //将信号添加到集合set里

 10    sigaddset(&set,SIGINT);

 11    //设置信号的屏蔽

 12//   sigprocmask(SIG_SETMASK,&set,NULL);

 13    sleep(10);

 14    //获取未决信号

 15    sigpending(&pset);

 16    //判断SIGINT是不是未决信号

 17    if(sigismember(&pset,SIGINT)==1){

 18        printf("SIGINT pending...\n");

 19     }

 20    return 0;

 21 }

tarena@tarena-virtual-machine:~/day31$./a.out

^C

作用:12 //    sigprocmask(SIG_SETMASK,&set,NULL); 

没有屏蔽ctrl+c的命令,即在睡眠期间,可以接受信号,按下ctrl+c就可以执行打断功能,就不存在未决信号。

二、                                有名管道

创建一个管道文件,一个进程往这个文件里写数据,一个进程从这个文件里读取数据,就此完成了两个进程间的通讯。

文件比较特殊,这个文件只是作为进程间通讯使用,文件的大小为0

管道的创建:

mkfifo(3)

#include<sys/types.h>

#include<sys/stat.h>

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

功能:创建一个管道文件

参数:

pathname:文件的路径

mode:文件具有的权限,需要考虑umask

返回值:0成功,-1失败,errno被设置

举例:processA.c 先执行,在这个进程中创建管道,往管道里写内容

 processB.c 后执行,从管道里读内容

processA.c 

  1 #include<stdio.h>

  2 #include<unistd.h>

  3 #include<sys/types.h>

  4 #include<sys/stat.h>

  5 #include<fcntl.h>

  6 int main(void){

  7    int fd,ret;

  8    //管道文件的创建

  9    ret=mkfifo("myfifo",0666);

 10    if(ret==-1){

 11        perror("mkfifo");

 12        return 1;

 13     }

 14    //打开管道文件

 15    fd=open("myfifo",O_RDWR);

 16    if(fd<0){

 17        perror("open");

 18        return 0;

 19     }

 20    //往管道文件里写一个字符串

 21    write(fd,"tang",5);

 22    sleep(10);

 23    close(fd);

 24    return 0;

25 }

tarena@tarena-virtual-machine:~/day31$ls –l

prw-rw-r--1 tarena tarena    0  9月  8 11:11 myfifo

-rw-rw-r-- 1 tarenatarena  471  9月  8 11:11 processA.c

补充

1、文件类型:p代表有名管道文件   l 软连接文件  d文件夹问价

2、协议就是规则

processB.c  :

  1 #include<stdio.h>

  2 #include<sys/types.h>

  3 #include<sys/stat.h>

  4 #include<unistd.h>

  5 #include<fcntl.h>

  6 int main(void){

  7    int fd;

  8    char buf[10]={0};

  9    //打开管道文件

 10    fd=open("myfifo",O_RDONLY);

 11    if(fd<0){

 12        perror("open");

 13        return 1;

 14     }

 15    //从管道文件里读取字符串

 16    read(fd,buf,5);

 17    //将读取到的内容输出到屏幕

 18    write(1,buf,7);

 19    write(1,"\n",1);

 20    close(fd);

 21    return 0;

 22 }

tarena@tarena-virtual-machine:~/day31$gcc processA.c -o pa

tarena@tarena-virtual-machine:~/day31$gcc processB.c -o pb

在一个终端运行:

tarena@tarena-virtual-machine:~/day31$rm myfifo

tarena@tarena-virtual-machine:~/day31$./pa

另一个终端运行:

tarena@tarena-virtual-machine:~/day31$./pb

tang

说明:A进程向B进程传送字符串“tang”

 

可以使用mkfifo命令创建一个管道文件

mkfifo –m 0666 yfifo

processC.c:从管道文件里写

processD.c:从管道文件里读

 

processC.c

  1 #include<stdio.h>

  2 #include<unistd.h>

  3 #include<sys/types.h>

  4 #include<sys/stat.h>

  5 #include<fcntl.h>

  6 int main(void){

  7    int fd;

  8    //打开管道文件

  9    fd=open("yfifo",O_RDWR);

 10    if(fd<0){

 11        perror("open");

 12        return 0;

 13     }

 14    //往管道文件里写一个字符串

 15    write(fd,"tang",5);

 16    close(fd);

 17    return 0;

 18 }

processD.c

  1 #include<stdio.h>

  2 #include<sys/types.h>

  3 #include<sys/stat.h>

  4 #include<unistd.h>

  5 #include<fcntl.h>

  6 int main(void){

  7    int fd;

  8    char buf[10]={0};

  9    //打开管道文件

 10    fd=open("yfifo",O_RDONLY);

 11    if(fd<0){

 12        perror("open");

 13        return 1;

 14     }

 15    //从管道文件里读取字符串

 16    read(fd,buf,5);

 17    //将读取到的内容输出到屏幕

 18    write(1,buf,7);

 19     write(1,"\n",1);

 20    close(fd);

 21    return 0;

 22 }

tarena@tarena-virtual-machine:~/day31$mkfifo –m 0666 yfifo

tarena@tarena-virtual-machine:~/day31$gcc processC.c -o pc

tarena@tarena-virtual-machine:~/day31$gcc processD.c -o pd

在一个终端执行:

tarena@tarena-virtual-machine:~/day31$ ./pd

(等待进程c输入)

在另一个终端执行:

tarena@tarena-virtual-machine:~/day31$./pc

则第一个终端结果为:

tarena@tarena-virtual-machine:~/day31$./pd

tang

无名管道和有名管道的区别

无名管道应具有亲缘关系的进程

无名管道不需要进程具有任何关系

 

三、                                有名管道

用户时间

内核时间

睡眠时间

实用计时器

虚拟计时器

真是计时器

setitimer(2)

#include<sys/time.h>

int getitimer(intwhich, struct itimerval *curr_value);

int setitimer(intwhich, const struct itimerval *new_value, struct itimerval *old_value);

功能:设置时间的间隔值

参数:

Which参数的取值:

ITIMER_REAL        SIGALRM

ITIMER_VIRTUAL    SIGVTALRM

ITIMER_PROF        SIGPROF        

new_value:

struct itimerval {

               struct timeval it_interval; /*next value */

               struct timeval it_value;    /* current value */

           };

struct timeval {

               long tv_sec;                /* seconds */

               long tv_usec;               /* microseconds */

           };

old_value:NULL

返回值:

0        成功,   -1  失败

举例:timer.c

  1 /*初始间隔5秒,5秒后,每一秒发送一个SIGALRM*/

  2#include<stdio.h>

  3#include<signal.h>

  4#include<sys/time.h>

  5 //信号处理函数

  6 voidhandle(int signum){

  7     if(signum==SIGALRM){

  8         printf("haha...\n");

  9     }

 10 }

 11 intmain(){

 12     struct itimerval itm;

 13     signal(SIGALRM,handle);

 14     //设置初始间隔值

 15     itm.it_value.tv_sec=5;

 16     itm.it_value.tv_usec=0;

 17     //设置重复间隔值

 18     itm.it_interval.tv_sec=1;

 19     itm.it_interval.tv_usec=0;

 20    if(setitimer(ITIMER_REAL,&itm,NULL)==-1){

 21         perror("setitimer");

 22         return 1;

 23     }

24    while(1);

 25     return 0;

 26 }

tarena@tarena-virtual-machine:~/day31$ ./a.out

haha...

haha...

 

信号小结:

1、  信号是异步的,是进程间通讯的一种方式

2、  信号的产生、信号的递达、信号未决、信号的捕获

3、  信号的处理方式有三种

a)      SIG_DFL 默认处理

b)     SIG_IGN 信号忽略

c)      用户自定义处理函数

4、  可重入函数:函数中只出现auto局部变量,这样的函数称为可重入函数

5、  信号的阻塞和未决信号  sigset_t

6、  信号的产生(kill、raise)

7、Sleep、usleep、pause、alarm   重点

8、  Setitimer实现定时器

 

四、                      进程间通讯

 进程间通讯的几种方式

1、  管道(有名管道、无名管道)

2、  信号

3、  环境变量(父子进程的传递)

4、  IPC进程间通讯

5、  网络

 

IPC进程间通讯、

1、消息队列

ftok (3)

#include <sys/types.h>

#include <sys/ipc.h>

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

功能:将文件的路径和proj_id转换成一个IPC键值。

参数:

pathname:文件的路径

proj_id: 0~~255

返回值:

成功返回键值,失败返回-1,erron被设置

 

msgget (2)    

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

intmsgget(key_t key, int msgflg);

功能:获取一个消息队列的id

返回值:

参数:

Key:通过ftokl(3)获取键

msgflg:IPC_CREAT|IPC_EXCL 如果消息队列存在,调用失败

如果不存在,创建消息队列。创建消息队列的时候还需要指定消息队列的权限,权限等同于open时候的权限

 

消息队列的消息模板

<linux/msg.h>

Struct msgbuf{

                   long msgtype;

                   char mtext[1];

}

 

 

msgrcv:(3)

#include <sys/msg.h>

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

功能:从消息队列中读取消息到msgp指定的地址。读取内容的长度由msgsz指定。读取的消息类型由msgtype参数指定。

参数:

msgflg:0

msqid:消息队列的id

msgtyp:消息队列的类型

msgsz:消息内容的长度

msgp:消息队列变量的地址

返回值:

-1:代表失败

成功返回获取到的消息队列的内容的长度

msgsnd (3)

#include <sys/msg.h>

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

功能:向msqid指向的消息队列发送长度为msgsz的消息

参数:

msqid:消息队列的id

msgp:消息队列的具体内容,里面包含消息队列的类型,还有消息队列的内容

msgsz:消息队列的内容的长度

返回值:-1代表失败,errno被设置   0代表成功

 

 

举例: send.c recv.c

vi send.c

消息队列的发送

  1 #include<stdio.h>

  2 #include<sys/types.h>

  3 #include<sys/ipc.h>

  4 #include<sys/msg.h>

  5 #include<string.h>

  6 #define FILENAME "."

  7 #define PROJ_ID 32

  8 int main(void){

  9     key_t key;

 10     int qid;

 11     //定义消息模版的结构体

 12     struct mymsgbuf{

 13         long msgtype;

 14         char str[256];

 15     }msgbuff;

 16     //初始化消息变量

 17     msgbuff.msgtype=3;

 18     strcpy(msgbuff.str,"this is atest");

 19     //产生一个键值

 20     key=ftok(FILENAME,PROJ_ID);

 21     if(key==-1){

 22         perror("ftok");

 23         return 1;

24     }

 25     //获取和键值对应的消息队列的id

 26     qid=msgget(key,IPC_CREAT|0660);

 27     if(qid==-1){

 28         perror("msgget");

 29         return 2;

 30     }

 31     printf("msgget successful! \n");

 32     int len=sizeof(structmymsgbuf)-sizeof(long);//内容的长度

 33     if(msgsnd(qid,&msgbuff,len,0)==-1){

 34         perror("msgsnd");

 35         return 3;

 36     }

 37     return 0;

 38 }

 

vi recv.c

消息队列的接收

  1 #include<stdio.h>

  2 #include<sys/types.h>

  3 #include<sys/ipc.h>

  4 #include<sys/msg.h>

  5 #define FILENAME "."

  6 #define PROJ_ID 32

  7 int main(void){

  8     struct mymsgbuf{

  9         long msgtype;

 10         char str[256];

 11     }msgbuff;

 12     key_t key;

 13     int qid;

 14     key=ftok(FILENAME,PROJ_ID);

 15     qid=msgget(key,IPC_CREAT|0660);

 16     if(qid==-1){

 17         perror("msgget");

 18         return 1;

 19     }

 20     printf("msggetsuccessful...\n");

 21     int len=sizeof(structmymsgbuf)-sizeof(long);

 22     if(msgrcv(qid,&msgbuff,len,3,0)==-1){

 23         perror("msgrcv");

24         return 2;

 25     }

 26     printf("message is%s\n",msgbuff.str);

 27     return 0;

 28 }

 

tarena@tarena-virtual-machine:~/day31$ gcc send.c -o send

tarena@tarena-virtual-machine:~/day31$ gcc recv.c -o recv

tarena@tarena-virtual-machine:~/day31$ ./send

msgget successful!

tarena@tarena-virtual-machine:~/day31$ ipcs

 

------ Shared Memory Segments --------

key        shmid      owner     perms      bytes      nattch    status     

------ Message Queues --------

key        msqid      owner     perms      used-bytes   messages   

0x20014e2b 0          tarena     660       256          1          

 

tarena@tarena-virtual-machine:~/day31$ ./recv

msgget successful...

message is this is a test

tarena@tarena-virtual-machine:~/day31$ ipcs

------ Message Queues --------

key        msqid      owner     perms      used-bytes   messages   

0x20014e2b 0          tarena     660       0            0        

 

补充:查看消息队列命令

ipcs 命令用于查看

 

 

明天讲:

2、共享内存 (进程映射到同一块内存)

3、信号量集

 

 

0 0
原创粉丝点击