键
每个内核中的IPC结构(消息队列、信号量或共享存储段)都用一个非负整数的标识符加以引用,为了对一个消息队列发送或取消息,只需要知道其队列标识符。
键是在用户空间的,标识符是在内核空间的,一个标识符映射一个键。
用户
键
1 ==> 65536
2 ==> 98305
调用get函数(msgget()、semget()和shmget())时必须指定键表示引用哪一个IPC对象。
int msgget(key_t key, int msgflg);
int semget(key_t key, int nsems, int semflg);
int shmget(key_t key, size_t size, int shmflg);
#include
struct
{
};
使用IPC对象时应注意的问题:
1)进程终止了IPC对象不会被删除,直到
2)这些IPC结构在文件系统中没有名字,于是就不得不增加新的命令ipcs和ipcrm。
消息队列:
消息队列是消息的链接表,存放在内核中并由消息队列标识符标识。
msgget()用于创建一个消息队列或打开一个现存的队列。
msgsnd()将新消息添加到队列尾端。每个消息包含一个正长整型类型字段,一个非负长度以及实际数据字节,所有这些都在将消息添加到队列时,传递给msgsnd()。
msgrcv()用于从队列中取消息。我们不一定要以先进先出次序取消息,也可以按消息的类型字段取消息。
每个队列都有一个msqid_ds结构与其相关联:
struct
{
};
此结构规定了队列的状态,类似与struct
Linux可发送最长消息的字节数:8192字节;
一个特定队列的最大字节数:16384字节;
系统中最大消息队列数:取决于操作系统;
int
flag:IPC_CREAT,IPC_EXCL,权限组合
功能:打开一个现存队列或创建一个新队列。
若执行成功,msgget()返回消息队列ID,此后,该值就可被用于其他三个消息队列函数。
创建1号消息队列,一定要在flag中指定IPC_CREAT表示创建消息队列,IPC_EXCL表示如果消息队列存在则出错返回EEXIST:
if(msgq_id=msgget(1,IPC_CREAT|IPC_EXCL|0777)<0)
如果已经创建消息队列,如何获得消息队列的标识符?
int msgq_id;
msgq_id=msgget(1,0);
int
cmd参数 说明对由msqid指定的队列要执行的命令:
IPC_STAT
IPC_SET 按由buf指向结构中的值,设置与此队列相关结构中的下列四个字段:msg_perm.uid、msg_per.gid、msg_perm.mode和msg_qbytes。此命令只能由下列两种进程执行:一种是超级用户进程;一种是其有效用户ID等于msg_perm.cuid或msg_perm.uid的进程。
IPC_RMID
例如:msgctl(1,IPC_RMID,NULL);
int msgsnd(int
成功返回0,失败返回-1;
消息结构体,这个结构体需要自己定义:
struct
{
};
参数flag:
可以指定为IPC_NOWAIT,这类似于文件I/O的非阻塞标志,若消息队列已满,或队列中的字节总数等于系统限制值,则指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN。
如果没有指定IPC_NOWAIT(通常设为0),则进程阻塞直到下述情况出现为止:
1、有空间可以容纳要发送的消息;
2、从系统中删除了此队列,此时,msgsnd()返回EIDRM表示该消息队列被删除了。
3、捕捉到一个信号,并从信号处理程序返回,此时,msgsnd()返回EINTR表示被信号中断了。
msgsnd.c、msgrcv.c ==> 讲解消息队列的基本使用方法。
方法:
msgsnd.c向消息队列中发送消息,msgrcv.c从消息队列中取出消息。
msgsnd.c
#include
//定义消息结构体
typedef struct
{
}Msg;
int main()
{
}
msgrcv.c
#include
typedef struct
{
}Msg;
int main()
{
return
}
结果: 从消息队列里拿到第2个消息是:Hello father.
消息队列标识==>标识消息队列ID
消息类型==>标识消息ID
ssize_t msgrcv(int
成功返回消息的数据部分的长度,出错返回-1.
若msgrcv成功执行时,消息队列中的消息取走了就没了。
ptr:指向一个消息结构体(一个长整型数,跟随其后的是存放实际消息数据的缓冲区)
nbytes:数据缓冲区的长度,若返回的消息大于nbytes,而且在flag中设置了MSG_NOERROR,则该消息被截短(在这种情况下,不通知我们消息截短了,消息的截去部分被丢弃),如果没有设置这一标志,而消息又太长,则出错返回E2BIG(消息仍留在队列中)
type==0:获得消息队列中第一个消息
type>0 :获得消息队列中类型为type的第type个消息
type<0 :获得消息队列中小于或等于type绝对值的消息(类型最小的)
type非0用于以非先进先出次序读消息。
flag
1、有了指定类型的消息,则取走消息,成功返回。
2、从系统中删除了此队列(出错返回-1,errno设置为EIDRM)
3、捕捉到一个信号并从信号处理程序返回(msgrcv返回-1,errno设置为EINTR)。
flag
练习:
fork_msg.c ==> 讲解消息队列在父子进程间通信。
方法:
父进程:传递2个整数放到消息队列里,并把子进程运算结果从消息队列里取出来
子进程:拿到父进程的2个整数进行相加把结果放回消息列队里
思路:
创建1号消息队列拿到它的内核标识符,fork(),父进程向消息队列里放2条1类消息,每条消息包含了一个整数,再以阻塞方式读取子进程放的2类消息,子进程读取父进程的2条1类消息,经过计算以后放1条2类消息放到消息队列里让父进程去取,父进程取出2类消息打印后把消息队列删除掉,并wait()子进程。
fork_msg.c
#include
typedef struct
{
}Msg;
int main()
{
return
}