ipcs是Linux下显示进程间通讯设施状态的工具。能够显示消息队列、共享内存和信号量的信息。对于程序员很是有用,普通的系统管理员通常用不到此指令。程序员
ipcs -q 查看系统使用的IPC队列资源ide
ipcs -m 查看系统使用的IPC共享内存资源函数
ipcs -s 查看系统使用的IPC信号量资源工具
ipcs -a命令能够查看当前使用的共享内存、消息队列及信号量全部信息测试
ipcs -p命令能够获得与共享内存、消息队列相关进程之间的消息ui
ipcs -u命令能够查看各个资源的使用总结信息,其中能够看到使用的信号量集的个数、信号量的个数,spa
以及消息队列中当前使用的消息个数总数、占用的空间字节数。命令行
默认不加参数时,使用的参数是 -a (all,显示全部)code
pcs -l命令能够查看各个资源的系统限制信息,能够看到系统容许的最大信号量集及信号量个数限制、最大的消息队列中消息个数等信息。对象
yxg@k8s:~$ ipcs -l
------ Messages Limits --------
max queues system wide = 32000 //系统最多的消息队列数量
max size of message (bytes) = 8192 //单个消息的最大字节数
default max size of queue (bytes) = 16384 //单个消息的最大字节数
------ Shared Memory Limits --------
max number of segments = 4096
max seg size (kbytes) = 18014398509465599
max total shared memory (kbytes) = 18014398442373116
min seg size (bytes) = 1
------ Semaphore Limits --------
max number of arrays = 32000
max semaphores per array = 32000
max semaphores system wide = 1024000000
max ops per semop call = 500
semaphore max value = 32767
这个限制能够经过增长内核参数 semmni 的取值来解决,该参数定义了系统可以拥有的信号量集合的
总数。Linux 能够动态调整大多数内核IPC 参数值的大小,也能够静态地修改
一、建立消息队列
消息队列是随着内核的存在而存在的,每一个消息队列在系统范围内对应惟一的键值。要得到一个消息队列的描述符,
只须要提供该消息队列的键值便可,该键值一般由函数ftok返回。
key_t ftok(const char *pathname, int proj_id);
ftok函数根据pathname和proj_id这两个参数生成惟一的键值。
pathname:must refer to an existing, accessible file,在系统中必定要存在,且进程有访问权限。
proj_id:的取值范围为1-255
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h>
int main() { int i = 0; for(i=0;i<5;i++) { printf("key[%d] = %lu\n", i, ftok(".", i)); } return 0; }
ftok返回的键值能够提供给函数msgget,
msgget根据这个键值建立一个新的消息队列或者访问一个已存在的消息队列。
int msgget(key_t key, int msgflg);
参数key即为ftok函数的返回值。msgflag是一个标志参数。
如下是msgflg的可能取值:
IPC_CREAT:若是内核中不存在键值与key相等的消息队列,则新建一个消息队列;若是存在这样的消息队列,返回消息队列的描述符。
IPC_EXCL:和IPC_CREAT一块儿使用,若是对应键值的消息队列已经存在,则出错,返回-1
上述msgflg参数为模式标志参数,使用时须要与IPC对象存取权限(如0600)进行|运算来肯定消息队列的存取权限.
若是用msgget建立了一个新的消息队列对象时,则msqid_ds结构成员变量的值设置以下:
msg_qnum、msg_lspid、msg_lrpid、 msg_stime、msg_rtime设置为0。
msg_ctime设置为当前时间。
msg_qbytes设成系统的限制值。
msgflg的读写权限写入msg_perm.mode中。
msg_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
注意:IPC_EXCL单独使用是没有任何意义的。
该函数若是调用成功返回一个消息队列的描述符,不然返回-1
二、写消息队列
建立了一个消息队列后,就能够对消息队列进行读写了。函数msgsnd用于向消息队列发送(写)数据。
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msqid:函数向msgid标识的消息队列发送一个消息
msgp:指向发送的消息。
msgsz:要发送消息的大小,不包含消息类型占用的4个字节。
msgflg:操做标识位。能够设置为0或者IPC_NOWAIT。若是为0,则当消息队列已满的时候,msgsnd将会阻塞,直到消息可写进消息队列;若是msgflg
为IPC_NOWAIT,当消息队列已满的时候,msgsnd函数将不等待当即返回。
msgsnd函数成功返回0,失败返回-1。常见错误码有:EAGAIN,说明消息队列已满。
EIDRM:说明消息队列已被删除
EACCES:说明无权访问消息队列
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <string.h>
//用户自定义消息缓冲
struct mymsgbuf{ long msgtype; char buf[256]; }; int main() { struct mymsgbuf mymsgbuffer; int msglen = 0; int i = 0; int msgkey = 0; int qid = 0;//消息队列标识符 //获取键值
msgkey = ftok(".", 11); qid = msgget(msgkey, IPC_CREAT|0660); printf("msgget return %d\n", qid); //填充消息结构,发送到消息队列
mymsgbuffer.msgtype = 4; strcpy(mymsgbuffer.buf, "manman"); msglen = sizeof(struct mymsgbuf) - 4; if (msgsnd(qid, &mymsgbuffer, msglen, 0) == -1) { perror("msgsnd error\n"); exit(1); } return 0; }
root@wilson-software:~/Project/xa# ./main
msgget return 0
执行程序以后,就向消息队列放入了一条消息,经过指令ipcs查看:
------ Message Queues --------
key msqid owner perms used-bytes messages
0x0b014424 0 root 660 256 1
三、读消息队列
消息队列中放入数据后,其余进程就能够读取其中的消息了。读取消息的系统调用为
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数含义:
msqid:消息队列描述符
msgp:读取的消息存储到msgp指向的消息结构中
msgsz:消息缓冲区的大小
msgtyp:为请求读取的消息类型
msgflg:操做标志位。msgflg能够为IPC_NOWAIT, MSG_EXCEPT ,MSG_NOERROR
0:表示忽略
IPC_NOWAIT:若是没有知足条件的消息,调用当即返回,此时错误码为ENOMSG
若是不指定这个参数,那么进程将被阻塞直到函数能够从队列中获得符合条件的
消息为止。若是一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回若是进
程在阻塞等待过程当中收到了系统的中断信号,EINTR 就会被返回。
MSG_EXCEPT :与msgtype配合使用,返回队列中第一个类型不为msgtype的消息
MSG_NOERROR:若是队列中知足条件的消息内容大于所请求的msgsz字节,则把该消息截断,截断部分将被丢弃。
若是不指定这个参数,E2BIG 将被返回,而消息则留在队列中不被
取出。当消息从队列内取出后,相应的消息就从队列中删除了。
可利用ipcrm -q 294912删除该消息队列。(294912为msgqid)由于消息队列是随内核持续存在的,在程序中若不利用msgctl函数或在命令行用ipcrm命令显式地删除,该消息队列就一直存在于系统中。另外信号量和共享内存也是随内核持续存在的
在读取前:
------ Message Queues --------
key msqid owner perms used-bytes messages
0x0b014424 0 root 660 256 1
在读取后
key msqid owner perms used-bytes messages
0x0b014424 0 root 660 0 0
调用msgrcv函数的时候,成功会返回读出消息的实际字节数,不然返回-1。
常见错误码有:
E2BIG: 表示消息的长度大于msgsz
EIDRM:表示消息队列已被删除
EINVAL:说明msgqid无效或msgsz小于0
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <stdlib.h> #include <string.h>
//用户自定义消息缓冲
struct mymsgbuf{ long msgtype; char buf[256]; }; int main() { struct mymsgbuf mymsgbuffer; int msglen = 0; int i = 0; int msgkey = 0; int qid = 0;//消息队列标识符 //获取键值
msgkey = ftok(".", 11); qid = msgget(msgkey, IPC_CREAT|0660); printf("msgget return %d\n", qid);
msglen = sizeof(struct mymsgbuf) - 4;
//上面的程序中发送的消息类型是4
//注意,msgrcv的msgflg参数可设置msgrcv函数是不是阻塞的,经测试msgflg是0的状况会阻塞,直到获取到消息 if (msgrcv(qid, &mymsgbuffer, msglen, 4, 0) == -1) { perror("msgsnd error\n"); exit(1); } printf("get message:%s\n", mymsgbuffer.buf); return 0; }
运行结果:
root@wilson-software:~/Project/xa# ./main
msgget return 0
get message:manman
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
利用上面提到的msgrcv()对消息长度的处理,咱们可使用下面的方法来检查队列内
是存在符合条件的信息:
int peek_message( int qid, long type )
{
int result, length;
if((result = msgrcv( qid, NULL, 0, type, IPC_NOWAIT)) == -1)
{
if(errno == E2BIG)
return(TRUE);
}
return(FALSE);
}
这里咱们将msgp 和msgsz 分别设为NULL 和零。而后检查函数的返回值,若是是E2BIG
则说明存在符合指定类型的消息。一个要注意的地方是IPC_NOWAIT 的使用,它防止了阻塞