39
Inter-Process Comm unication based on Linux3.2 孟孟 孟孟0512-68839302 孟孟孟孟@mengning997 孟孟孟孟@ 孟孟 V5 E-mail [email protected] 孟孟http://staff.ustc.edu.cn/~mengning 孟孟 孟孟孟孟孟孟孟孟孟孟孟孟孟孟孟孟孟 166 孟孟孟孟 A302 孟 2012 孟 5 孟

Inter-Process Communication based on Linux3.2

  • Upload
    ovidio

  • View
    57

  • Download
    0

Embed Size (px)

DESCRIPTION

Inter-Process Communication based on Linux3.2. 孟宁 电话:0512-68839302 腾讯微博:@mengning997 新浪微博:@孟宁V5 E-mail:[email protected] 主页:http://staff.ustc.edu.cn/~mengning 地址:苏州工业园区独墅湖高等教育区仁爱路166号明德楼A302室. 20 1 2 年 5 月. Inter-Process Communication. IPC,Inter-Process Communication - PowerPoint PPT Presentation

Citation preview

Page 1: Inter-Process Communication  based on Linux3.2

Inter-Process Communication

based on Linux3.2

孟宁电话: 0512-68839302 腾讯微博: @mengning997 新浪微博: @ 孟宁 V5E-mail : [email protected]主页: http://staff.ustc.edu.cn/~mengning地址:苏州工业园区独墅湖高等教育区仁爱路 166 号明德楼 A302室

2012 年 5 月

Page 2: Inter-Process Communication  based on Linux3.2

Inter-Process Communication

♦ IPC , Inter-Process Communication

♦ Unix 系统提供的基本的 IPC 包括:– 信号– 管道和 FIFO (有名管道)– 消息队列– 信号量– 共享内存区– 套接字

Page 3: Inter-Process Communication  based on Linux3.2

信号♦ 信号在最早的 Unix 系统中就已经被引入了,

用于在用户态进程间通信。♦ 内核也用信号通知进程系统所发生的事情♦ 信号是很短的消息♦ 标准信号没有给参数、消息或是其他相随

的信息留有空间♦ 通常使用一个数字来标识一个信号♦ 信号可以被发送到一个进程或一组进程。

Page 4: Inter-Process Communication  based on Linux3.2

信号的作用♦ 使用信号的两个主要目的是:

– 让进程知道已经发生了一个特定的事件– 强迫进程执行它自己代码中的信号处理程序

• 很多应用程序提供自己的信号处理程序• 系统也会定义一些缺省的信号处理程序

Page 5: Inter-Process Communication  based on Linux3.2

信号的生成♦ 异常

– 当一个进程出现异常(比如试图执行一个非法指令,除 0 ,浮点溢出等),内核通过向进程发送一个信号来通知进程异常的发生

♦ 其他进程 – 一个进程可以通过 kill 或是 sigsend 系统调用

向另一个进程或一个进出组发送信号。一个进程也可以向自身发送信号

♦ 终端 – 某些键盘字符如 ctrl+c 等会向终端的前台进程

发送信号

Page 6: Inter-Process Communication  based on Linux3.2

信号的生成♦ 作业控制

– 发送信号给那些想要读或写终端的后台进程。比如shell 使用信号来管理前台和后台进程

♦ 配额限制 – 当一个进程使用超过分配给它的 cpu 时间或是文件大

小的限制,内核发送一个信号给这个进程 ♦ 通知

– 一个进程也许要求能被通知某些事件的发生。比如设备已经就绪等待 I/O 操作

♦ 闹钟 – 定时器产生的信号,由内核发送给进程

Page 7: Inter-Process Communication  based on Linux3.2

Linux/i386 中的部分信号

Page 8: Inter-Process Communication  based on Linux3.2

Linux/i386 中的部分信号

Page 9: Inter-Process Communication  based on Linux3.2

信号举例: “ Ctrl+c” 组合键

♦ 假设用户在 console 下按下“ ctrl+c” ,这将产生终端中断– tty驱动程序能识别出这个组合键,并向自己的

前台进程发送一个 SIGINT 信号。– 当对应进程被调度执行时,它将在上下文切换返回到用户态时检查到这个信号。

–此外,通常前台进程就是被 ctrl+c 中断的current 进程。当进程从中断返回时,也会检查到这个信号。

–检查到信号后,系统就会让进程执行相应的动作。

Page 10: Inter-Process Communication  based on Linux3.2

信号举例:异常♦ 前面讲过,异常也是通过信号来实现的。♦ 当程序发生除 0错误或是有非法指令时,

将引起一个内核态的 trap 。♦ 内核 trap 处理程序识别出这个异常并发送

合适的信号到当前进程。♦ 当 trap 处理程序将要返回到用户态时,会检查并发现信号,进程可能就会被终止。

Page 11: Inter-Process Communication  based on Linux3.2

异常处理程序

异常处理程序发出的信号

Page 12: Inter-Process Communication  based on Linux3.2

与信号相关的系统调用

Page 13: Inter-Process Communication  based on Linux3.2

信号处理过程

Page 14: Inter-Process Communication  based on Linux3.2

给特定进程发送信号的函数♦ int kill(pid_t pid,int signo)♦ int raise(int signo) 向进程本身发送信号♦ int sigqueue(pid_t pid, int sig, const union

sigval val)♦ unsigned int alarm(unsigned int seconds)专门为 SIGALRM 信号而设,在指定的时间 seconds秒后,将向进程本身发送SIGALRM 信号,又称为闹钟时间。

♦ int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));

Page 15: Inter-Process Communication  based on Linux3.2

信号传递的两个不同阶段♦ 信号产生

– 内核更新进程描述符中跟信号相关的数据结构来表示一个信号被发送给了这个进程

♦ 信号传递– 内核强迫目标进程通过以下方式对信号作出反映:

• 或改变目标进程的执行状态,• 或开始执行一个特定的信号处理程序,• 或者两者都是

Page 16: Inter-Process Communication  based on Linux3.2

管道( pipe )♦ 管道是所有 Unix都提供的一种 IPC机制

– 管道是半双工的,数据只能向一个方向流动;• 一个进程将数据写入管道,

另一个进程从管道中读取数据• 数据的读出和写入:

写入的内容每次都添加在管道缓冲区的末尾,每次都是从缓冲区的头部读出数据。

–需要双方通信时,需要建立起两个管道;–只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);

Page 17: Inter-Process Communication  based on Linux3.2

在 shell 中使用管道的例子♦ 命令:“ ls | more”

使用 pipeline “|” 将两个命令” ls” 和“ more”连接起来,使得 ls 的输出成为more 的输入

♦ 也可以使用如下的两个命令–命令 1 :“ ls > tmp”把 ls 的输出重定向到 tmp

文件中;–命令 2 :”more < tmp”把more 的输入重定

向到 tmp 文件

Page 18: Inter-Process Communication  based on Linux3.2

创建一个管道♦ 管道可看成是被打开的文件,但并没有真实的

文件与之对应♦ pipe() 系统调用用来创建一个新的管道

– #include <unistd.h>– int pipe(int filedes[2]);

♦ 管道两端分别用描述符 filedes[0] 和 filedes[1]描述♦ 管道两端的功能是固定的:

– filedes[0]只能用于读,称为管道读端;– filedes[1]只能用于写,称为管道写端。– 若试图从写端读,或者向读端写都将导致错误发生。

♦ 一般文件的 I/O函数都可用于管道,如close 、 read 、 write 等

Page 19: Inter-Process Communication  based on Linux3.2

使用管道的典型程序♦ 管道只能在具有亲缘关系的进程之间进行

通信– 通过 fork传递管道的描述符

♦ 任意的两个进程不可能共享同一个管道–无法打开已经存在的管道

Page 20: Inter-Process Communication  based on Linux3.2

if (pipe(filedes)<0){...}if ((pid=fork())<0){...}if (pid>0){ // this is parent

close(filedes[0]);printf("this is parent\n");write(filedes[1],"this is from parent\n",19);sleep(1);wait4();return 0;

}if (pid==0){//this is child

char buf[1024];ssize_t strlen;close(filedes[1]);printf("this is child\n");strlen=read(filedes[0],buf,1024);if (strlen>0){

buf[strlen]='\0';printf("%s\n",buf);

}return 0;

}

$ gcc testpipe.c -o testpipe$ ./testpipethis is parentthis is childthis is from parent

Page 21: Inter-Process Communication  based on Linux3.2

FIFO

♦ 管道的一个重大限制是它没有名字,因此只能用于具有亲缘关系的进程间通信,在有名管道( named pipe 或 FIFO )提出后,该限制得到了克服。

♦ FIFO ,有名管道– 特殊的文件类型:

1 ,严格遵循先入先出的读写规则2 ,类似管道,在文件系统中不存在数据块,而是与一块内核缓冲区相关联3 ,有名字, FIFO 的名字包含在系统的目录树结构中,可以按名访问

Page 22: Inter-Process Communication  based on Linux3.2

创建一个有名管道 /FIFO

其他操作使用 open, close, read, write等普通文件操作

Page 23: Inter-Process Communication  based on Linux3.2

FIFO 举例♦ 创建一个 FIFO : createfifo.c

♦ 向 FIFO 写: writefifo.c

♦ 从 FIFO 读: readfifo.c

Page 24: Inter-Process Communication  based on Linux3.2

createfifo.c

#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>

int main(void){

umask(0);if(mkfifo("myfifo",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)){

perror("mkfifo error");exit(1);

}return 0;

}

Page 25: Inter-Process Communication  based on Linux3.2

writefifo.c#include <stdio.h>#include <sys/types.h>#include <stdlib.h>

int main(void){

FILE * out_file;

if ((out_file=fopen("myfifo","w"))==NULL){

perror("open fifo error");exit(1);

}

fwrite("you are welcome\n",1,20,out_file);fclose(out_file);return 0;

}

Page 26: Inter-Process Communication  based on Linux3.2

readfifo.c#include <stdio.h>#include <sys/types.h>#include <stdlib.h>int main(void){

FILE * in_file;int count=0;char buf[20];if ((in_file=fopen("myfifo","r"))<0){

perror("open fifo for read error");exit(1);

}

while(count==0)count=fread(buf,1,20,in_file);

printf("%s",buf);fclose(in_file);return 0;

}

Page 27: Inter-Process Communication  based on Linux3.2

消息队列♦ 消息队列就是一个消息的链表。♦ 可以把消息看作一个记录,具有特定的格式以及特定的优先级。

♦ 对消息队列有写权限的进程可以按照一定的规则向消息队列添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。

Page 28: Inter-Process Communication  based on Linux3.2

消息队列的操作♦ 创建消息队列

– int msgget(key_t key, int msgflg) – 根据给定的键值,返回对应的消息队列。若能找到,则返回已有的;否则,创建一个新的

♦ 发送消息– int msgsnd(int msqid, // 目标消息队列

struct msgbuf *msgp, // 待发送的消息int msgsz, // 消息的大小int msgflg); // 标志

– 对于发送消息来讲, msgflg 有意义的标志为IPC_NOWAIT :指明在消息队列没有足够空间容纳要发送的消息时, msgsnd 是否等待

♦ 接收消息– int msgrcv(int msqid, //msqid为消息队列描述字

struct msgbuf *msgp, // 消息返回后存储这里int msgsz, // 指定消息内容的长度long msgtyp, //请求读取的消息类型nt msgflg);

– 读消息标志msgflg 可以为以下几个常量的或:– IPC_NOWAIT :如果没有满足条件的消息,立即返回,此时, errno=ENOMSG – IPC_EXCEPT :与msgtyp>0 配合使用,返回队列中第一个类型不为msgtyp 的消息 – IPC_NOERROR :如果队列中满足条件的消息内容大于所请求的 msgsz 字节,则把该消息截断,截断部分将丢失。

Page 29: Inter-Process Communication  based on Linux3.2

信号量♦ Semphore ,用来对资源进行并发控制访问♦ 通常是一个计数器

– 如果资源可用,值 >0– 如果不可用,值 <=0

♦ 当进程需要访问资源,但资源不可用时,将计数值 -1 ,并阻塞

♦ 当进程释放资源,使得资源有资源可用时,就唤醒被阻塞的进程

Page 30: Inter-Process Communication  based on Linux3.2

使用信号量互斥int main(void){

key_t unique_key;int id;struct sembuf lock_it;union semun options;int i;pid_t pid;

unique_key=ftok(".",'m');

id=semget(unique_key,1,IPC_CREAT|IPC_EXCL|0666);

options.val=1;

semctl(id,0,SETVAL,options);

i=semctl(id,0,GETVAL);printf("GETVAL, i=%d\n",i);

lock_it.sem_num=0;lock_it.sem_op=-1;lock_it.sem_flg=IPC_NOWAIT;

if ((pid=fork())<0){

perror("fork failed");exit(1);

}

if (pid>0){// this is parentwhile(semop(id,&lock_it,1)) {

printf("parent: cant get, must wait\n");sleep(1);

}printf("this is parent using the semphore\n");sleep(2);lock_it.sem_op=1;semop(id,&lock_it,1);printf("the semaphore is released by parent\n");wait(pid);semctl(id,0,IPC_RMID);

}else{

// this is childwhile(semop(id,&lock_it,1)) {

printf("can't get, must wait\n");sleep(1);

}printf("this is child using the semaphore\n");sleep(2);lock_it.sem_op=1;semop(id,&lock_it,1);printf("the semaphore is released by child\n");

}示例程序仅仅是为了说明进程之间的互斥

Page 31: Inter-Process Communication  based on Linux3.2

共享内存♦ 允许两个或多个进程通过把公共数据放入

一个共享内存区来访问它们♦ 两个进程通过共享内存进行通信

– testshm.c– testshm2.c

Page 32: Inter-Process Communication  based on Linux3.2

共享内存的操作

获得或创建一个共享内存区的 IPC 标志符

将一个共享内存区“附加”到一个进程上,使得进程可以访问共享内存区的内容进程通过 shmaddr 指定并获得共享内存区在该进程中的起始地址

将指定位置的共享内存区从进程中分离出去

Page 33: Inter-Process Communication  based on Linux3.2

testshm.ckey_t key;int shm_id;const int shm_size=4096;char * shm_addr;

key=ftok(".",'m');shm_id=shmget(key,shm_size,IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);

shm_addr=(char*)shmat(shm_id,0,0);

sprintf(shm_addr,"hello, this is 11111111\n");printf("111111:");printf(shm_addr);sleep(10);printf("111111:");printf(shm_addr);shmdt(shm_addr);shmctl(shm_id,IPC_RMID,0);return 0;

Page 34: Inter-Process Communication  based on Linux3.2

testshm2.c

key_t key;int shm_id;const int shm_size=4096;char * shm_addr;

key=ftok(".",'m');shm_id=shmget(key,shm_size,S_IRUSR|S_IWUSR);

shm_addr=(char*)shmat(shm_id,0,0);

printf("22222222:");printf(shm_addr);sprintf(shm_addr,"this is 22222222\n");shmdt(shm_addr);return 0;

Page 35: Inter-Process Communication  based on Linux3.2

套接字 socket

♦ 套接字不仅可以用来实现网络间的进程通信,也可以用来实现本地的进程间通信

♦ 相关调用包括:– Socket– Listen– Bind– Connect/accept– Send/recv , read/write– Close– …

Page 36: Inter-Process Communication  based on Linux3.2
Page 37: Inter-Process Communication  based on Linux3.2

TCP服务器编程模型socket(...);

        bind(...);         listen(...);         while(1) //循环服务器        {                 accept(...);                 while(1)                 {                         read(...);                         process(...);                         write(...);                 }                 close(...);         }

Page 38: Inter-Process Communication  based on Linux3.2

TCP客户端编程模型socket(…)

connect(…)

while(1)

{read(…)

write(…)

}

close(…)

Page 39: Inter-Process Communication  based on Linux3.2

谢谢大家!

教育的核心,不是教学,而是学习; 成长的核心,不是解答,而是提问;领导的核心,不是管理,而是服务。

参考资料:《深入理解 Linux 内核》第三版本课件代码参考 http://219.219.220.231/raw-attachment/wiki/Linux2012/ipc.rar