1.创建一个消息队列,向此消息队列发送一个字节的消息,然后调用MSGCTL函数的IPC_STAT.获得消息队列情况,
调用system函数,执行ipcs -q命令,
最后删除此消息队列;
2.用ftok函数创建一个消息队列,有排他性选项;
1) int flag=IPC_MODE|IPC_CREAT;//用int存放这些标示
2)switch(c)
{
case 'e'://是'e'不是"e"
3) key=ftok(argv[optind],0);//optind用法以及ftok函数
3.创建一个专门发送消息的程序
1) struct msgbuf *msgptr;/*如何用结构体指针*/
msgptr=calloc(.....)
2)byte=atoi(argv[2]); /*把入参传给int类型时,要用atoi*/
3)msgptr->mtype=type;//指针要用->,不是.
4.接受,
5删除队列的
6创建一个文件做标识符,传给一个接受消息的程序
1) if(optind!=2)// 不知道用optind什么效果 ,optind 始终为1,所以不可以当判断条件
2)msgid=atoi(argv[1]);//msgid=argv[1]; 入参一定转换
3)buf=malloc(MAXSIZE);//要记得给结构体分配大小
4)type = %ld",n,buf->mtype);//struct msgbuf 中的mtype是long型
7.完成一个客户服务端的例子,用两个消息队列;
1)由windows写好的makefile传到服务器上,执行make命令,有时候会报错,stop。。。之类的,这时候,直接在后台
用vi建立makefile就可以
2)服务端:
定义一个结构体
struct A{
....
}AA
定义结构体变量,struct A myA;
这里不可以用struct AA myA;会报错error #2070: incomplete type is not allowed
给结构体指针分配空间
struct A *pmyA;<-这里是指针不是对象
pmyA=calloc(...);
结构体对象,调用其内部成员 myA.成员名
结构体指针,调用其内部成员pmyA->成员名
注意.与->
使用fopen 或者 open
FILE *fd;//int fd; fopen返回FILE *,所以不可以用inr类型
int fd;//open返回int型
fopen与fgets配合,open与read配合;
if( (fd=fopen(buf.msg,"r")) ==0 )
//fopen(buf.msg,"r") 不可以为fopen(buf.msg,O_RDONLY), O_RDONLY用于open
if( (fd=open(buf.msg,O_RDONLY)) <0 )
while(fgets(buf.msg,MAXSIZE,fd)!=0)//每次取一行
while( (n=read(fd,buf.msg,MAXSIZE))!=0 ) //把文件内容全部取出
//fgets会在字符串末尾加上/n结束,调用msgsnd的时候还要去'/n'
消息结构体中的类型一定要赋值
buf.mtype=MSGTYPE; //如果不赋值类型,就无法发送出去,msgsnd返回-1
函数结尾要关闭文件描述符
msgsnd 与 msgrcv
n=msgrcv(readfd,&buf,MAXSIZE,MSGTYPE,0)) ==0 )// n为客户msgsnd的第三个参数,不是MAXSIZE
msgsnd(writefd,&buf,n,0);//msgsnd的第三个参数不是消息最大字节数,而是要发送的消息大小,不加结构体的类型的大小
客户端与服务端的msgsnd 成功后都返回的0,不是发送的字节;
服务端的msgrcv 成功后返回客户端发送过来的数据的大小,而客户端的 msgrcv却只返回1;
while( (rcvlen=msgrcv( ...)>0) )
{
//printf("%s/n",buf.msg); // 用printf可以全部打印出来,而用write只输出一个字符,难道是第三个参数rcvlen的原因,因为,每次rcvlen返回是1;;最后发现,输出msgrcv的内容时,不用msgrcv的返回值长度,而用strlen(buf.msg)
//write(1,buf.msg,rcvlen);
write(1,buf.msg,strlen(buf.msg));
}
8.复用消息
复用消息就是说了两个特性:
一是V队列不用先进先出,与管道和fifo不一样;
二是用消息类型可以标识消息是哪个进程发送的,所以,进程调用msgrcv的时候,第三个参数用进程号+100;
9.复用消息例子
一个服务器,两个客户,一个消息队列;
客户把进程ID传给服务端,服务端返回内容的时候,将ID放入type;客户端接收相应类型的消息;
类型1是客户到服务端的消息类型;
缺陷:有死锁的存在,因为多个客户和一个服务端这种模型,是存在死锁的
vim:远程目录,%创建新文件
msgrcv,msgsnd 都在一个循环中,do while 或者 for
服务器端:
1)msgsrv接收的过来命令的形式是:pid pathname
注意:字符串末尾没有'/n',所以接受到字符串以后要加'/n';
2)当消息队列没有消息时,msgsrv返回0,在跳到循环头;
3)'/n'与'/0'区别
4)msgbuf.mtext[n]='/n';错,如果以这种方式结尾,则用open( msgbuf.mtext,O_RDONLY )时,会报-1错误
msgbuf.mtext[n]='/0';正确,
//这里用的是消息队列返回的值n,有的系统上msgrcv成功返回为1,而不是消息的大小,所以,也可以用n=strlen(msgbuf.mtex),msgbuf.mtext[n]='/n'
5)if( (pos=strchr(msgbuf.mtext," ")) ==0)//strchr与strstr函数,两者都返回地址,strchr第二个参数是int,strstr第二个参数是char*,注意,如果找空格,第二个参数应该为" ",而不是' '
HP下面的警告:
a value of type "int" cannot be
assigned to an entity of type "char *"
6)*pos++=0;
//为什么不是*pos=0; 因为*pos++=0 就是(*pos)=0;pos++,为了atol做处理,并且使pos指向了pathnam
7)atol(msgbuf.mtext);//atol跳过前面空格,直到遇到'/0
8)while( (n=read(fd,msgbuf.mtext,MAXDATE)>0) )
//第三个参数是指定的文件的大小,但是这个大小是不确定的,第二个参数是个buf,但是这个buf能不能是之前用的消息队列结构体的buf
9) if( (n=msgsnd(msgid,&msgbuf,n,0))==-1 )//msgsnd返回-1是错误
客户端:
1)
char *ptr;
//定义一个ptr指针,用这个指针指向消息缓冲区,将pid和pathname放入消息缓冲区
ptr=mbuf.mtext+len;//ptr指向mtext末尾
2)snprintf函数用法
3)
if((fptr=fgets(ptr,MAXDATE-len,stdin))==0 && ferror(stdin))
//通过ptr指针,对mbuf.mtext进行操作
//如果第三个参数为0,就会出core,必须引用stdlib.h,用stdin
//对返回时char *函数的处理
//stdin =0 ,stdout=1在哪个头文件?stdlib.
//fgets会对字符串尾加'/n'
4)
write(1,mbuf.mtext,n)
第一个参数用1,而用stdout则报错,这点奇怪
9.复用消息例子(多子进程)
1)在使用msgget(key,MODE)如果没定义下面权限
#define MODE MSG_R|MSG_W|MSG_R>>3|MSG_W>>3|MSG_R>>6|MSG_W>>6|IPC_CREAT
//如果没有上面的权限 消息队列会有异常内容mbuf.mdat=p
2)
if( (pos=strstr(mbuf.mdate," "))==NULL)//不用strchr,因为其第二个参数为int,
如果使用了strchr
这里会出core
*pos++=0;//这里出core
3)
//char * 的用法,指向数组的末尾
char *pos;
len=strlen(cbuf.mdate);
pos=cbuf.mdate+len;