分类: LINUX
2010-10-30 20:34:12
进程间通信(IPC)
进程的地址空间相互独立的,因此进程间交互数据必须采用专门的通信机制。
Linux进程间通信有以下几种方式:
管道(pipe),有名管道(named pipe),信号量(semophore),消息队列(message queue),信号(signal),共享内存(shared memory),套接字(socket).
1.管道
定义:一种两个进程间单向的机制,传递数据具有单向性,又称半双工管道(可以通过建立两个管道实现全双工通信)。
特点:管道只能用于具有亲缘关系的两个进程间通信,管道没有名字,并且管道传递的是一种无格式的字节流。管道是一种存在于内存的特殊的文件,当创建管道时,系统分配一个页面作为数据缓冲区,进行管道通信的两个进程,读取这个页面进行通信。
1>管道
函数: int pipe(int fd[2])
管道两端分别可用管道读端(fd[0])和管道写端fd[1]表示。
创建方法:
先调用pipe()函数建立一个管道,再调用fork()函数创建进程,然后父进程关闭管道读端,只执行)(write)写操作;子进程关闭管道写端,只进行读操作(read),也可调换顺序。进行进程间通信时,子进程和父进程共享同一文件描述符。
注意:当子进程调用exec执行另一程序时,这时,可以将子进程的文件描述符重定向到标准输入(通过调用dup()或dup2()实现),即新程序从标准输入获取数据时,实际相当于从父进程获取数据。
2>有名管道(FIFO)
定义:有名管道是一个设备文件,且有名管道在实际磁盘中以FIFO的文件格式存在。因此调用有名管道时必须先调用open()函数使其打开。
特点:不必拘泥于具有亲缘关系的管道才可进行通信。
创建有名管道有两种方法:
1.在 shell 下交互的建立有名管道(mknod,mkfifo);
int mknod(const char *path,mode_t, mod,dev_t dev);
int mkfifo(const char *path,mode_t mod);
path为创建有名管道路径,mod为创建模式,dev设备值(进一步证明有名管道是个设备文件
2.程序中使用系统函数建立.
Eg:
mkfifo(“tmp/fifo”,S_IFIFO | 0660);
注意 :
创建有名管道时如果使用O_RDWR打开不会阻塞,若使用O_RDONLY 或O_WRONLY方式打开有名管道会阻塞,直到有写方或读方打开管道。
3>消息队列
定义:是一个存放在内核中的消息链表,每个消息队列由消息队列标识符标识。
特点:消息队列存放在内核中,要删除一个消息队列只能通过显示的删除和内核重启(系统重启)进行。
首先介绍几个数据结构:
1.消息缓冲结构
struct msgbuf{
long mtype; //消息类型
char mtext[1]; //消息内容(可自定义为 struct student stu)
};
2.msqid_ds内核数据结构
struct
msqid_ds
{
struct msqid_ds {
struct
ipc_perm msg_perm;//一个ipc_perm数据结构,保存存取权限,队列用户ID组ID
struct
msg *msg_first; /* 指向队列中的第一条消息*/
struct
msg *msg_last; /* 指向队列中最后一条消息 */
__kernel_time_t msg_stime; /* 向队列发送最后一条消息得时间*/
__kernel_time_t
msg_rtime; /* 向消息队列取最后一条队列的时间*/
__kernel_time_t msg_ctime; /* 最后一次更改消息队列的时间*/
unsigned
long msg_lcbytes; /* 32位再利用域*/
unsigned
long msg_lqbytes; /* 同上*/
unsigned
short msg_cbytes; /* 消息队列中所有消息占得字节数*/
unsigned
short msg_qnum; /* 队列中消息得数目 */
unsigned
short msg_qbytes; /* 队列的最大字节数*/
__kernel_ipc_pid_t msg_lspid; /* 向队列发送最后一条消息得进程ID
*/
__kernel_ipc_pid_t msg_lrpid; /* 向消息队列读取最后一条信息的进程ID*/
};
3.ipc_perm内核数据结构
struct ipc_perm { key_t key; /* 创建消息队列用到的键值key*/ uid_t uid; /* 消息队列的用户ID*/ gid_t gid; /* 消息队列的组ID */ uid_t cuid; /* 创建消息队列的进程用户ID*/ gid_t cgid; /* 创建消息队列的进程组ID*/ unsigned short mode; /* 权限*/ unsigned short seq; /* 序列号 */ };
一。应用:
1.获取键值
key_t ftok(const char *pathname,int proj_id);
pathname 路径(存在且有权访问) proj_id 1-255
2.创建消息队列
int msgget(key_t key,int msgflg)
key 为获取的键值 msgflg为标志参数,取值为IPC_CREAT(消息队列存在则返回描述符,不存在则新建) IPC_EXCL(对应消息队列描述符存在则出错,和第一个参数配合使用,单独无效)
3.写消息队列
int msgsnd(int msqid,strcuct msgbuf *msgp,size_t msgsz,int magflg);
4.读消息队列
int msgrcv(int msqid,struct msgbuf *msgp,size_t msgsz,long int msgtyp,int msgflg);
二.获取设置消息队列属性
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
通过msgctl函数用户可以获取或设置消息队列的属性。
参考书籍《linux c编程实战》