Lixnux的消息创建、发送与接收
什么是消息?
消息(message)是一个格式化的可变长的信息单元。消息机制允许由一个进程给其它任意的进程发送一个消息。当一个进程收到多个消息时,可将它们排成一个消息队列。消息使用二种重要的数据结构:一是消息首部,其中记录了一些与消息有关的信息,如消息数据的字节数;二个消息队列头表,其每一表项是作为一个消息队列的消息头,记录了消息队列的有关信息。
消息的系统函数用法
1. msgget( )
创建一个消息,获得一个消息的描述符。核心将搜索消息队列头表,确定是否有指定名字的消息队列。若无,核心将分配一新的消息队列头,并对它进行初始化,然后给用户返回一个消息队列描述符,否则它只是检查消息队列的许可权便返回。
msgqid=msgget(key,flag)
key
是用户指定的消息队列的名字;flag
是用户设置的标志和访问方式。
如 IPC_CREAT |0400 是否该队列已被创建。无则创建,是则打开;
IPC_EXCL |0400 是否该队列的创建应是互斥的。
msgqid 是该系统调用返回的描述符,失败则返回-1。
2. msgsnd()
发送一消息。向指定的消息队列发送一个消息,并将该消息链接到该消息队列的尾部。
msgsnd(msgqid,msgp,size,flag)
msgqid是返回消息队列的描述符;
msgp是指向用户消息缓冲区的一个结构体指针。缓冲区中包括消息类型和消息正文。
即
{
long mtype; /消息类型/
char mtext[ ]; /消息的文本/
}
size指示由msgp指向的数据结构中字符数组的长度;即消息的长度。
flag规定当核心用尽内部缓冲空间时应执行的动作:进程是等待,还是立即返回。设置为0表示阻塞方式,设置IPC_NOWAIT 表示非阻塞方式
3. msgrcv( )
msgrcv(msgqid,msgp,size,type,flag)
除了type参数,其他同上。
type:分成三种情况处理:
type=0,接收该队列的第一个消息,并将它返回给调用者
type为正整数,接收类型type的第一个消息
type为负整数,接收小于等于type绝对值的最低类型的第一个消息
Linux下查看消息的有关命令
查看消息队列等等相关信息
ipcs
只查看消息队列
ipcs -p
根据消息队列的msqid删除消息队列
ipcrm -q 163840
调试例子
1、通过消息机制实现进程间的数据通信,client向server发送“I am client!”
client.c
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <stdlib.h>
#define MSGKEY 75
//1.新建一个结构体,用于存放将要发送的消息
struct msgform
{
long mtype;
char mtext[1000];
} msg;
int msgqid = -1;
void client()
{
int i;
//2.创建一个名为为75可读可写的消息队列
msgqid = msgget(MSGKEY, 0777); /*打开75#消息队列*/
if(msgqid == -1){
printf("client的消息队列创建失败
");
}
//3.向消息队列发送消息
strcpy(msg.mtext,"I am client!");
for (i = 3; i >= 1; i--)
{
msg.mtype = i;//i为消息的类型
printf("(server)send: %s
",msg.mtext);
msgsnd(msgqid, &msg, 1024, 0); /*发送消息*/
}
exit(0);
}
main()
{
client();
}
server.c
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#define MSGKEY 75
//1.新建一个结构体,用于存放将要接受的消息
struct msgform
{
long mtype;
char mtext[1000];
} msg;
int msgqid;
void server()
{
//2.创建一个名为为75可读可写的消息队列
msgqid = msgget(MSGKEY, 0777 | IPC_CREAT); /*创建75#消息队列*/
//3.监听消息队列中的消息
do
{
msgrcv(msgqid, &msg, 1030, 0, 0); /*接收消息:倒数第二个0代表接受任何消息*/
printf("(server)received: %s
",msg.mtext);
} while (msg.mtype != 1);//当接受到消息时,返回值为1,跳出循环
msgctl(msgqid, IPC_RMID, 0); /*删除消息队列,归还资源*/
exit(0);
}
main()
{
server();
}
运行结果:
Linux的共享存储区通信
什么是共享存储?
共享存储如同其名字所隐喻的,是物理存储器中一段可由两个以上的进程共享的存储空间。共享存储段具有大小和物理存储地址。想要访问共享存储段的进程可以连接这段存储区域到自己的地址空间中任何适合的地方,其他进程也一样。这样,多个进程便可以访问相同的物理存储。其中箭头表示进程的逻辑存储与物理存储的映射关系。
共享储存区通信的函数用法
1、shmget( )
创建、获得一个共享存储区。
shmid=shmget(key,size,flag)
key是共享存储区的名字
size是其大小(以字节计)
flag是用户设置的标志
2、shmat( )
共享存储区的附接。从逻辑上将一个共享存储区附接到进程的虚拟地址空间上。
virtaddr=shmat(shmid,addr,flag)
shmid是共享存储区的标识符
addr是用户给定的,将共享存储区附接到进程的虚地址空间
flag规定共享存储区的读、写权限,以及系统是否应对用户规定的地址做舍入操作,该系统调用的返回值是共享存储区所附接到的进程虚地址viraddr。
3、shmdt( )
把一个共享存储区从指定进程的虚地址空间断开。
shmdt(addr)
addr是要断开连接的虚地址,亦即以前由连接的系统调用shmat( )所返回的虚地址。调用成功时,返回0值,调用不成功,返回-1。
4、shmctl( )
共享存储区的控制,对其状态信息进行读取和修改。
shmctl(shmid,cmd,buf)
shmid是上边那个id
buf是用户缓冲区地址
cmd是操作命令
2、通过共享内存机制实现进程间的数据通信,client向server发送“I am client!”
sharem.c
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define SHMKEY 75
int shmid, i;
char *addr;
void client()
{
int i;
//1.取得共享存储区id
shmid = shmget(SHMKEY, 1024, 0777);
//2.使当前的子进程的虚拟地址空间附接到共享储存区,shmat函数中shimid为共享存储区id,第二个0为地址,第三个0表示可读可写,shmat的返回值是共享区所附接到的虚地址addr
printf("client进程获取存储区id成功
");
addr = shmat(shmid, 0, 0); /*获得共享存储区首地址:这个addr其实就是个字符串指针指向的一个区域,因为父进程和子进程都能访问到这个地址,因此子进程向地址中写入数据,父进程取出数据,这样就完成了共享存储区的信息通信*/
printf("client进程附接存储区地址成功
");
//3.向共享存储区写信息
for (i = 3; i >= 0; i--)
{
strcpy(addr, "I am client!");
while (strcmp(addr, "waiting") != 0)
;
printf("(client) reading:%s
", addr);
}
printf("client进程发送信息成功
");
//4.发送信息完毕,发送一个结束的标志信息
strcpy(addr, "endding");
exit(0);
}
void server()
{
//1.取得共享存储区id
shmid = shmget(SHMKEY, 1024, 0777 | IPC_CREAT); /*创建共享存储区*/
printf("server进程获取存储区id成功
");
//2.使当前的子进程的虚拟地址空间附接到共享储存区
addr = shmat(shmid, 0, 0); /*获取首地址*/
printf("server进程附接存储区地址成功
");
//3.不断向共享存储区读消息
do
{
strcpy(addr, "waiting");
while (strcmp(addr, "waiting") == 0)
;
printf("(server) received:%s
", addr);
} while (strcmp(addr, "endding") != 0);
printf("server进程发送信息成功
");
shmctl(shmid, IPC_RMID, 0); /*撤消共享存储区,归还资源*/
exit(0);
}
main()
{
while ((i = fork()) == -1)
;
if (!i) //令一个子进程执行server
server();
system("ipcs - m"); //终端执行ipcs - m
while ((i = fork()) == -1)
;
if (!i) //另一个子进程执行client
client();
wait(0);
wait(0);
}
运行结果: