消息通信 message
消息是进程间通信的一种重要方式,通常由客户端和服务器端组成。服务器以特定的键值创建一个消息队列,根据约定的消息格式填充要发送的消息和数据类型,把他插入消息队列。而在客户端,根据已知的键值和指定地点类型编码,接收对应的数据。和共享内存的方式相比,不用自己维护消息队列,可以集中精力关注数据传输,但不足的是,对于需要共享或者传输比较复杂数据结构的应用,它就显得不太灵活。
消息通信重要的函数组包括:
int
msgget(key_t key, int msgflg);
The
msgget() system call returns the System V message queue identifier
associated with the value of the key argument. A
new message
queue is created if key has the value IPC_PRIVATE or key isn‘t
IPC_PRIVATE, no message queue with the given key
key exists,
and IPC_CREAT is specified in msgflg.
If msgflg
specifies both IPC_CREAT and IPC_EXCL and a message queue already
exists for key, then msgget() fails with errno
set to
EEXIST. (This is analogous to the effect of the combination O_CREAT
| O_EXCL for open(2).)
Upon
creation, the least significant bits of the argument msgflg define
the permissions of the message queue. These per‐
mission bits
have the same format and semantics as the permissions specified for
the mode argument of open(2). (The exe‐
cute
permissions are not used.)
int
msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t
msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int
msgflg);
DESCRIPTION
The msgsnd()
and msgrcv() system calls are used, respectively, to send messages
to, and receive messages from, a System V
message
queue. The calling process must have write permission on the message
queue in order to send a message, and read
permission to
receive a message.
The msgp
argument is a pointer to a caller-defined structure of the following
general form:
struct
msgbuf {
long
mtype; /* message type, must be > 0 */
char
mtext[1]; /* message data */
};
The mtext
field is an array (or other structure) whose size is specified by
msgsz, a nonnegative integer value. Messages
of zero
length (i.e., no mtext field) are permitted. The mtype field must
have a strictly positive integer value. This
value can be
used by the receiving process for message selection (see the
description of msgrcv() below).
int
msgctl(int msqid, int cmd, struct msqid_ds *buf);
DESCRIPTION
msgctl()
performs the control operation specified by cmd on the System V
message queue with identifier msqid.
The msqid_ds
data structure is defined in <sys/msg.h> as follows:
struct
msqid_ds {
struct
ipc_perm msg_perm; /* Ownership and permissions */
time_t
msg_stime; /* Time of last msgsnd(2) */
time_t
msg_rtime; /* Time of last msgrcv(2) */
time_t
msg_ctime; /* Time of last change */
unsigned
long __msg_cbytes; /* Current number of bytes in
queue
(nonstandard) */
msgqnum_t
msg_qnum; /* Current number of messages
in
queue */
msglen_t
msg_qbytes; /* Maximum number of bytes
allowed
in queue */
pid_t
msg_lspid; /* PID of last msgsnd(2) */
pid_t
msg_lrpid; /* PID of last msgrcv(2) */
};
The ipc_perm
structure is defined as follows (the highlighted fields are settable
using IPC_SET):
struct
ipc_perm {
key_t
__key; /* Key supplied to msgget(2) */
uid_t
uid; /* Effective UID of owner */
gid_t
gid; /* Effective GID of owner */
uid_t
cuid; /* Effective UID of creator */
gid_t
cgid; /* Effective GID of creator */
unsigned
short mode; /* Permissions */
unsigned
short __seq; /* Sequence number */
};
Valid values
for cmd are:
IPC_STAT
Copy
information from the kernel data structure associated with msqid into
the msqid_ds structure pointed to by buf.
The
caller must have read permission on the message queue.
IPC_SET
Write
the values of some members of the msqid_ds structure pointed to by
buf to the kernel data structure associated
with
this message queue, updating also its msg_ctime member. The
following members of the structure are updated:
msg_qbytes,
msg_perm.uid, msg_perm.gid, and (the least significant 9 bits of)
msg_perm.mode. The effective UID of
the
calling process must match the owner (msg_perm.uid) or creator
(msg_perm.cuid) of the message queue, or the
caller
must be privileged. Appropriate privilege (Linux: the
CAP_SYS_RESOURCE capability) is required to raise the
msg_qbytes
value beyond the system parameter MSGMNB.
IPC_RMID
Immediately
remove the message queue, awakening all waiting reader and writer
processes (with an error return and
errno
set to EIDRM). The calling process must have appropriate privileges
or its effective user ID must be either
that of
the creator or owner of the message queue. The third argument to
msgctl() is ignored in this case.
IPC_INFO
(Linux-specific)
Return
information about system-wide message queue limits and parameters in
the structure pointed to by buf. This
structure
is of type msginfo (thus, a cast is required), defined in <sys/msg.h>
if the _GNU_SOURCE feature test
macro is
defined:
struct
msginfo {
int
msgpool; /* Size in kibibytes of buffer pool
used
to hold message data;
unused
within kernel */
int
msgmap; /* Maximum number of entries in message
map;
unused within kernel */
int
msgmax; /* Maximum number of bytes that can be
written
in a single message */
int
msgmnb; /* Maximum number of bytes that can be
written
to queue; used to initialize
msg_qbytes
during queue creation
(msgget(2))
*/
int
msgmni; /* Maximum number of message queues */
int
msgssz; /* Message segment size;
unused
within kernel */
int
msgtql; /* Maximum number of messages on all queues
in
system; unused within kernel */
unsigned
short int msgseg;
/*
Maximum number of segments;
unused
within kernel */
};
The
msgmni, msgmax, and msgmnb settings can be changed via /proc files of
the same name; see proc(5) for details.
MSG_INFO
(Linux-specific)
Return
a msginfo structure containing the same information as for
IPC_INFO, except that the following fields are
returned
with information about system resources consumed by message queues:
the msgpool field returns the number of
message
queues that currently exist on the system; the msgmap field
returns the total number of messages in all
queues
on the system; and the msgtql field returns the total number of bytes
in all messages in all queues on the
system.
MSG_STAT
(Linux-specific)
Return
a msqid_ds structure as for IPC_STAT. However, the msqid argument is
not a queue identifier, but instead an
index
into the kernel‘s internal array that maintains information about all
message queues on the system.
RETURN
VALUE
On success,
IPC_STAT, IPC_SET, and IPC_RMID return 0. A successful IPC_INFO or
MSG_INFO operation returns the index of the
highest used
entry in the kernel‘s internal array recording information about all
message queues. (This information can be
used with
repeated MSG_STAT operations to obtain information about all queues
on the system.) A successful MSG_STAT opera‐
tion returns
the identifier of the queue whose index was given in msqid.
On error, -1
is returned with errno indicating the error.
依赖的头文件包括:
#include
<sys/types.h>
#include
<sys/ipc.h>
#include
<sys/msg.h>
下面以具体可用的一个基于消息通信的服务端和客户端的代码为例:
服务端:test_msg_svc.c
#include<stdio.h>
#include<assert.h>
#include<inttypes.h>
#include
<string.h>
#include
<stdlib.h>
#include
<errno.h>
#include
<unistd.h>
#include
<sys/types.h>
#include
<sys/ipc.h>
#include
<sys/stat.h>
#include
<sys/msg.h>
#define
MSG_FILE "test_msg_clnt"
#define
BUFFER 255
#define
PERM S_IRUSR|S_IWUSR
struct
msgtype {
long
mtype;
char
buffer[BUFFER+1];
};
int
main()
{
struct
msgtype msg;
key_t
key;
int
msgid;
if((key=ftok(MSG_FILE,‘a‘))==-1)
{
{
fprintf(stderr,"Creat
Key Error:%s\a\n",strerror(errno));
exit(1);
}
if((msgid=msgget(key,PERM|IPC_CREAT|IPC_EXCL))==-1)
//if((msgid=msgget(key,PERM|IPC_EXCL))==-1)
{
fprintf(stderr,"Creat
Message Error:%s\a\n",strerror(errno));
exit(1);
}
while(1)
{
msgrcv(msgid,&msg,sizeof(struct
msgtype),1,0);
fprintf(stderr,"Server
Receive:%s\n",msg.buffer);
msg.mtype=2;
msgsnd(msgid,&msg,sizeof(struct
msgtype),0);
memcpy(msg.buffer,
"Hello", strlen("Hello") + 1);
msg.mtype=2;
msgsnd(msgid,&msg,sizeof(struct
msgtype),0);
}
exit(0);
}
客户端: test_msg_clnt.c:
#include<stdio.h>
#include<assert.h>
#include<inttypes.h>
#include
<string.h>
#include
<stdlib.h>
#include
<errno.h>
#include
<unistd.h>
#include
<sys/types.h>
#include
<sys/ipc.h>
#include
<sys/stat.h>
#include
<sys/msg.h>
#define
MSG_FILE "test_msg_clnt"
#define
BUFFER 255
#define
PERM S_IRUSR|S_IWUSR
struct
msgtype {
long
mtype;
char
buffer[BUFFER+1];
};
int
main(int argc,char **argv)
{
struct
msgtype msg;
key_t
key;
int
msgid;
if(argc!=2)
{
fprintf(stderr,"Usage:%s
string\n\a",argv[0]);
exit(1);
}
if((key=ftok(MSG_FILE,‘a‘))==-1)
{
fprintf(stderr,"Creat
Key Error:%s\a\n",strerror(errno));
exit(1);
}
if((msgid=msgget(key,PERM))==-1)
{
fprintf(stderr,"Creat
Message Error:%s\a\n",strerror(errno));
exit(1);
}
msg.mtype=1;
strncpy(msg.buffer,argv[1],BUFFER);
msgsnd(msgid,&msg,sizeof(struct
msgtype),0);
memset(&msg,‘\0‘,sizeof(struct
msgtype));
msgrcv(msgid,&msg,sizeof(struct
msgtype),2,0);
fprintf(stdout,"Client
receive:%s\n",msg.buffer);
msgrcv(msgid,&msg,sizeof(struct
msgtype),2,0);
fprintf(stdout,"Client
receive:%s\n",msg.buffer);
exit(0);
}
编译运行及其结果:
[[email protected]
testcases]$ gcc -o test_msg_svc test_msg_svc.c
[[email protected]
testcases]$ gcc -o test_msg_clnt test_msg_clnt.c
[[email protected]
testcases]$ ./test_msg_svc
Server
Receive:HaHi
Server
Receive:GdLuCK
[[email protected]
testcases]$ ./test_msg_clnt HaHi
Client
receive:HaHi
Client
receive:Hello
[[email protected]
testcases]$ ./test_msg_clnt GdLuCK
Client
receive:GdLuCK
Client
receive:Hello