在linux系统下
消息队列的聊天室实现的过程:
1.消息队列
消息队列是消息的链接表,存放在内核中并由消息队列标识符标识。我们将称消息队列为
“队列”,其标识符为“队列I D”。
m s g g e t用于创建一个新队列或打开一个现存的队列。
m s g s n d用于将新消息添加到队列尾端。每个消息包含一个正长整型类型字段,一个非负长度以及实际
数据字节(对应于长度),所有这些都在将消息添加到队列时,传送给m s g s n d。
m s g r c v用于从队列中取消息。
我们并不一定要以先进先出次序取消息,也可以按消息的类型字段取消息。
每个队列都有一个m s q i d d s结构与其相关。此结构规定了队列的当前状态。如图(1-1)
图(1-1)msqid_ds结构
调用的第一个函数通常是m s g g e t,其功能是打开一个现存队列或创建一个新队列。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int flag) ;
返回:若成功则为消息队列I D,若出错则为- 1
调用m s g s n d将数据放到消息队列上。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void * pt r, size_tnbytes, int flag) ;
返回:若成功则为0,若出错则为- 1
正如前面提及的,每个消息都由三部分组成,它们是:正长整型类型字段、非负长度
(nbytes)以及实际数据字节(对应于长度)。消息总是放在队列尾端。ptr指向一个长整型数,它包含了正整型消息类型,在其后立即跟随了消息数据。(若nbytes是0,则无消息
数据。)若发送的最长消息是5 1 2字节,则可定义下列结构:
struct mymesg {
long mtype; /* positive message type */
char mtext[512]; /* message dat,aof length n b y t e s * /
} ;
于是,p t r就是一个指向mymesg结构的指针。接收者可以使用消息类型以非先进先出的次序取消息。f l a g的值可以指定为IPC_NOWAIT。这类似于文件I / O的非阻塞I / O标志。若消息队列已满(或者是队列中的消息总数等于系统限制值,或队列中的字节总数等于系统限制值),则指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN。如果没有指定IPC_NO WAIT,则进程阻塞直到(a)有空间可以容纳要发送的消息,或( b)从系统中删除了此队列,或( c)捕捉到一个信号,并从信号处理程序返回。在第二种情况下,返回E I D R M(“标志符被删除”)。最后一种情况则返回E I N T R。注意,对消息队列删除的处理不是很完善。因为对每个消息队列并没有设置一个引用计数器(对打开文件则有这
种计数器),所以删除一个队列使得仍在使用这一队列的进程在下次对队列进行操作时出错返回。信号量机构也以同样方式处理其删除。删除一个文件则要等到使用该文件的最后一个进程关闭了它,才能删除文件的内容。msgrcv从队列中取用消息。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(intm s q i d, void *ptr, size_t nbytes, long type, int flag) ;
返回:若成功则为消息数据部分的长度,若出错则为- 1
如同msgsnd中一样,p t r参数指向一个长整型数(返回的消息类型存放在其中),跟随其后
的是存放实际消息数据的缓存。nbytes说明数据缓存的长度。若返回的消息大于nbytes,而且在f l a g中设置了MSGNOERROR,则该消息被截短(在这种情况下,不通知我们消
息截短了)。如果没有设置这一标志,而消息又太长,则出错返回E2BIG(消息仍留在队列中)。
参数type使我们可以指定想要哪一种消息:
type == 0 返回队列中的第一个消息。
type > 0 返回队列中消息类型为t y p e的第一个消息。
type < 0 返回队列中消息类型值小于或等于t y p e绝对值,而且在这种消息中,其类型值
又最小的消息。非0t y p e用于以非先进先出次序读消息。例如,若应用程序对消息赋优先权,那么t y p e就可以是优先权值。如果一个消息队列由多个客户机和一个服务器使用,那么t y p e字段可以用来包含客户机进程I D。可以指定flag值为IPC_NOWAIT,使操作不阻塞。这使得如果没有所指定类型的消息,则msgrcv出错返回ENOMSG。如果没有指定IPC _NOWAIT,则进程阻塞直至(a)有了指定类型的消息,或(b)从系统中删除了此队列(出错返回E I D R M),或(c)捕捉到一个信号并从信号处理程序返回(出错返回E I N T R)。实例一消息队列与流管道的时间比较如若需要客户机和服务器之间的双向数据流,
可以使用消息队列或流管道。
2.简单的消息队列聊天列子。
/*服务端的代码*/
/*server.c*/
/*作者:叶建敏*/
/*QQ:230817742*/
#include <sys/ipc.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
//以上为程序所必须的头文件
struct msgbuf
{
long mtype; //消息类型
char mtext[100]; //消息正文
};
//定义一个结构体msgbuf用来存放消息的类型和消息的正文
int main()
{
FILE *fp; //定义文件变量指针
key_t key;
pid_t pid;
int msgid; //队列ID号
struct msgbuf msg1,msg2; //定义两个结构体变量
char wbuf[800]="",my_name[20]="",others_name[20]="";
// 消息内容,本地名字,对方名字
key=ftok(".",0xFF); //调用ftok函数,产生标准的key
if((msgid=msgget(key,IPC_CREAT|0666))<0)
//调用msgget函数,创建和打开消息队列
{
perror("msgger error");
exit(0);
}
printf("plese input you name:");
pe=3; //消息类型为3,此消息接受让对方对方接受的对应的消息类型的姓名
,0,100);// 设置缓冲区的内容
fgets(wbuf,100,stdin);//将标准输入到wbuf缓冲区
wbuf[strlen(wbuf)-1]='\0';
strcpy(my_name,wbuf);//把wbuf里的内容复制到my_name
,wbuf);//
msgsnd(msgid,&msg1,),0);//把消息添加到消息队列中
msgrcv(msgid,&msg2,100,4,0);//根据消息队列的消息类型接受对应的消息对方的姓名
strcpy(others_);//根据上面获得的数据把对方的的名字存储到others_name,存储是根据消息号存储
fflush(stdout);
if((pid=fork())<0)//创建一个子进程
{
printf("erro");
exit(0);
}
if(pid==0)
{
while(1)
{
pe=1;
,0,100);//刷新
printf("%s:",my_name);
fgets(wbuf,100,stdin);
wbuf[strlen(wbuf)-1]='\0';
,wbuf);
msgsnd(msgid,&msg1,),0);
}
}else
{
while(1)
{
msgrcv(msgid,&msg2,100,2,0);
if((fp=fopen("","a+"))==NULL)
{
perror("打开失败记录");
return 0;
}
fprintf(fp,"%s:%s\n",others_);
fclose(fp);
printf("\r%s:%s\n%s:",others_,my_name);
fflush(stdout);
}
}
}
/*哭护短的代码*/
/*client.c*/
/*作者:叶建敏*/
/*QQ:230817742*/
#include <sys/ipc.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
struct msgbuf
{
long mtype; //消息类型
char mtext[100]; //消息正文
};
int main()
{
FILE *fp;
key_t key;
pid_t pid;
int msgid; //队列ID
struct msgbuf msg1,msg2;
char wbuf[800]="",my_name[20]="",others_name[20]="";
linux下的sleep函数 key=ftok(".",0xFF);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论