Chinaunix首页 | 论坛 | 博客
  • 博客访问: 13901
  • 博文数量: 14
  • 博客积分: 410
  • 博客等级: 下士
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-20 10:49
文章分类

全部博文(14)

文章存档

2011年(1)

2010年(13)

我的朋友
最近访客

分类: 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>消息队列

定义:是一个存放在内核中的消息链表,每个消息队列由消息队列标识符标识。

特点:消息队列存放在内核中,要删除一个消息队列只能通过显示的删除和内核重启(系统重启)进行。


首先介绍几个数据结构:

.消息缓冲结构

struct msgbuf{

long mtype; //消息类型

char mtext[1]; //消息内容(可自定义为 struct student stu)

};


.msqid_ds内核数据结构

struct msqid_ds
{
struct msqid_ds {
struct ipc_perm msg_perm;//
一个ipc_perm数据结构,保存存取权限,队列用户IDID

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编程实战》

阅读(350) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~