每个进程都有各自的进程地址空间,所以进程之间的交互就需要通过内核了.
进程间通信方式:
管道
命名管道
XSI IPC:
消息队列
信号量
共享内存
管道pipe
int pipe(int pipe fd[2]);
fd[0] 读文件描述符
fd[1] 写文件描述符
父进程创建管道,fork[子进程获得父进程打开的描述符]
管道只能实现单方向通信;
且因为实现,仅能父子进程间通信.或者同宗族进程通信,且其必须从公共祖先获得管道
命名管道
在文件系统中创建一个管道文件.使得进程都可以访问得到
shell方式创建命名管道
mknod - make block or character special files
mkfifo - make FIFOs (named pipes)
函数创建
int mkfifo(const char *pathname, mode_t mode);
int mkfifoat(int dirfd, const char *pathname, mode_t mode);
XSI IPC
消息队列
消息队列提供了一种向另一进程发送数据块的方法
消息队列是基于消息的,而管道是基于字节流的
lang@liang:~$ cat /proc/sys/kernel/msgmax 最大长度
8192
lang@liang:~$ cat /proc/sys/kernel/msgmnb 每个消息的总字节数
16384
lang@liang:~$ cat /proc/sys/kernel/msgmni 消息队列的总数
32000
内核为IPC维护的数据结构,消息队列,信号量,共享内存都有一个以下的数据类型
#cat /usr/include/linux/ipc.h
IPC对象数据结构
struct ipc_perm
{
__kernel_key_t key;
__kernel_uid_t uid;
__kernel_gid_t gid;
__kernel_uid_t cuid;
__kernel_gid_t cgid;
__kernel_mode_t mode;
unsigned short seq;
};
msg对象数据结构
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* first message on queue,unused */
struct msg *msg_last; /* last message in queue,unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};
相应函数
int msgget(key_t key, int msgflg) 获取msg结构
key 一个端口号或者由ftok获取
msgflg :
IPC_CREAT 不存在则创建,否则打开
IPC_EXCL 不存在新建,否则返回错误
两个参数一起使用,那么.不存在则创建一个并打开,否则返回-1
向队列发数据/获取数据
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可
定义的通用结构,形态如下:
struct msgstru{
long mtype; //大大于0
char mtext[用户指定大大小小];
};
msgtyp:从消息队列内读取的消息形态。如果值为零,则表示消息队列中的所有消息都会被读取。
flag为0 时阻塞方式,IPC_NOWAIT非阻塞
设置消息属性
int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
IPC_STAT : 该命令用来获取消息队列对应的 msqid_ds 数据结构,并将其保存到 buf 指定的地址空间。
IPC_SET : 该命令用用来设置消息队列的属性,要设置的属性存储在buf中。
IPC_RMID : 从内核中删除 msqid 标识的消息队列。
ftok函数
函数ftok把一个已存在的路径名和一个整数标识得转换成一个key_t值,称为IPC键:
key_t ftok(const char *pathname, int proj_id);
该函数把从pathname导出的信息与id的低序8位组合成一个整数IPC键。
信号量
信号量的本质是数据操作锁,她本省不具有数据交换的功能,而是通过控制其他通信资源来实现进程间通信,他本身只是一种外部资源的标识.
在这个过程中,信号量负责是数据操作的互斥,同步等功能
当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用.
大于0,资源可以请求,等于0,无资源可用,进程进入睡眠状态直到资源可用.
当进程不再使用该资源时,信号量+1,对信号量的操作均为原子操作,
信号量的工作原理
P/V
P:如果sv的值大于0,给他减一,;如果值为0 ,挂起该进程
V:如果有其他进程因为等待该sv而挂起,就让他恢复运行,如果没有进程等待,那么sv+1