一.题目名称
实现客户端与服务器端之间消息的一发一收
二.问题描述
实现客户端与服务器端之间消息的一发一收
软中断:
kill(pid,sig):发送信号
signal(sig,function):指定进程对信号sig的处理是调用函数func。
步骤:子先执行到signal,循环等待kill信号,父kill信号一发送,子接收到kill信号,继续执行下面的。为防止先发送kill,子进程还没有执行到signal,无限等待,可以在kill前加入sleep;
.Signal()信号的接受终止waiting()的问题:当signal信号未到时,wait_mark为1,执行waiting()循环等待。当接收到signal信号后,执行stop( )命令。令状态wait_mark变为0,waiting( )不等待。继续执行。
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
int wait_mark;
void waiting()
{
while(wait_mark!=0);
}
void stop()
{
wait_mark=0;
}
int main()
{
int p1,p2;
while((p1=fork())==-1);
if(p1>0) //p1父
{
while((p2=fork())==-1);
if(p2>0) //p2父
{
printf("parent\n");
sleep(5);
kill(p1,16); //发送信号16 p1:pid sig:16
kill(p2,17); //发送信号17 p2:pid sig:17
wait(0);
wait(0);
printf("parent process id killed!\n");
exit(0);
}
else{ //p2子
printf("p2\n");
wait_mark=1;
signal(17,stop); //接受信号17,调用函数stop mark=0 17:signal fuction:stop
waiting(); //循环 mark!=0时循环, 当接受到信号17时,执行stop 令mark=0,就不等待了
printf("child process 2 is killed by parent!\n");
exit(0);
}
}
else{ //p1子
printf("p1\n");
wait_mark=1;
signal(16,stop); //接受信号17,调用函数stop mark=0
waiting(); //循环 mark!=0时循环, 当接受到信号16时,执行stop 令mark=0,就不等待了
printf("child process 1 is killed by parent!\n");
exit(0);
}
return 0;
}
消息队列
msgget
if((msgid = **msgget**(IPC_PRIVATE,0666)) == -1)
msgget(IPC_PRIVATE,0666)
说明:IPC_PRIVATE key值,建立新的消息队列。0666 msgflag
返回值:-1 创建失败
发送的信息 用户需自定义缓冲区:定义成结构体类型 包括 msgtype 消息类型 和 msgtext 消息内容。
struct msgbuf{
long msgtype;
char msgtext[1024];
}sndmsg,rcvmsg;
sprintf(sndmsg.msgtext,str1); //把一个字符串放到一个已知的字符数组里
msgsnd
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgsnd(msgid,&sndmsg,sizeof(str1)+1,0) == -1
将msgp消息写入到标识符为msqid的消息队列
msgsz:消息大小
msgflg:0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列
返回值:0 成功 -1 错误
msgrcv
msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msgrcv(msgid,&rcvmsg,80,333,IPC_NOWAIT)
从标识符为msqid的消息队列读取消息并存于msgp中,读取后把此消息从消息队列中删除
msgsz:要接收消息的大小。
msgtyp:
等于 0:接收第一个消息
大于 0:接收类型等于msgtyp的第一个消息
小于 0:接收类型等于或者小于msgtyp绝对值的第一个消息
msgflg:IPC_NOWAIT:如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG
msgctl
int msgctl(int msqid, int cmd, struct msqid_ds *buf)
msgctl(msgid,IPC_RMID,0);
获取和设置消息队列的属性
代码:
#include<sys/types.h>
#include<sys/msg.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int msgid;
int status;
char str1[] = {"test message:hello!"};
char str2[] = {"test message:goodbye!"};
char str3[] = {"The third message!"};
struct msgbuf{
long msgtype;
char msgtext[1024];
}sndmsg,rcvmsg;
if((msgid = msgget(IPC_PRIVATE,0666)) == -1) //创建一个消息队列 key:IPC_PRI:建立新的消息队列 0666 返回值-1:失败
{
printf("msgget error!\n");
exit(254);
}
sndmsg.msgtype =111; //消息类型:111
sprintf(sndmsg.msgtext,str1); //把一个字符串放到一个已知的字符数组里
if(msgsnd(msgid,&sndmsg,sizeof(str1)+1,0) == -1) //把sndmsg的消息写入到msgid的消息队列,sizeof(str1)+1:消息大小 0:msgflg:消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列
{
printf("msgget error!\n");
exit(254);
}
sndmsg.msgtype =222;
sprintf(sndmsg.msgtext,str2);
if(msgsnd(msgid,&sndmsg,sizeof(str2)+1,0) == -1)
{
printf("msgget error!\n");
exit(254);
}
sndmsg.msgtype =333;
sprintf(sndmsg.msgtext,str3);
if(msgsnd(msgid,&sndmsg,sizeof(str3)+1,0) == -1)
{
printf("msgget error!\n");
exit(254);
}
if(status = msgrcv(msgid,&rcvmsg,80,0,IPC_NOWAIT)==-1)//从标识符为msgid的消息队列读取消息并存入rcvmsg。 80:要接受的消息大小 0:msgtype接受第一个消息。
{
printf("msg rcv error!\n");
exit(254);
}
printf("The receieved message:%s.\n",rcvmsg.msgtext);
msgctl(msgid,IPC_RMID,0);
exit(0);
}
当msgrcv 中的type =333, 接收类型等于333的第一个消息
0:
感悟+总结:
sndmsg.msgtype =111;
sprintf(sndmsg.msgtext,str1);
if(msgsnd(msgid,&sndmsg,sizeof(str1)+1,0) == -1)
{
printf("msgget error!\n");
exit(254);
}
sndmsg.msgtype =222;
sprintf(sndmsg.msgtext,str2);
if(msgsnd(msgid,&sndmsg,sizeof(str2)+1,0) == -1)
{
printf("msgget error!\n");
exit(254);
}
sndmsg.msgtype =333;
sprintf(sndmsg.msgtext,str3);
if(msgsnd(msgid,&sndmsg,sizeof(str3)+1,0) == -1)
{
printf("msgget error!\n");
exit(254);
}
if(status = msgrcv(msgid,&rcvmsg,80,0,IPC_NOWAIT)==-1)
当type为222时,输出goodbye
type为333时,输出str3
type为0时 输出str1 队列中的第一个数据
进程间的通信通过key来确定消息队列
#include<sys/types.h>
#include<sys/msg.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#define MSGKEY 75
struct msgform{
long mtype;
char msgtext[1030];
}msg;
int msgqid,i;
int main()
{
while((i=fork())==-1);
if(!i) SERVER();
while((i=fork())==-1);
if(!i) CLIENT();
wait(0);
wait(0);
}
void SERVER()
{
msgqid=msgget(MSGKEY,0777|IPC_CREAT);//找到内存中和key值相等的消息队列
do{
msgrcv(msgqid,&msg,1030,0,0);//从标识符为msgid的消息队列读取消息并存入msg。 1030:要接受的消息大小 0:msgtype接受第一个消息。0:flg
printf("(server)received message %d \n",msg.mtype);
}while(msg.mtype!=1);
msgctl(msgqid,IPC_RMID,0);
exit(0);
}
void CLIENT()
{
int i;
msgqid = msgget(MSGKEY,0777); //新建key为75的消息队列,0777是文件的权限
for(int i=10;i>=1;i--)
{
msg.mtype=i;
printf("(client)sent\n");
msgsnd(msgqid,&msg,1030,0);//把msg的消息写入到msgid的消息队列,1030:消息大小 0:msgflg:消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列
}
exit(0);
}
发送带有内容的消息
#include<sys/types.h>
#include<sys/msg.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#define MSGKEY 75
struct msgform{
long mtype;
char msgtext[1030];
}msg;
int msgqid,i;
void SERVER()
{
msgqid=msgget(MSGKEY,0777|IPC_CREAT);//找到内存中和key值相等的消息队列
do{
msgrcv(msgqid,&msg,1030,0,0);
printf("(server)received message %d \n",msg.mtype);
printf("%s",msg.msgtext);
}while(msg.mtype!=1);
msgctl(msgqid,IPC_RMID,0);
exit(0);
}
void CLIENT()
{
int i;
char string_i[5];
msgqid = msgget(MSGKEY,0777); //新建key为75的消息队列,0777是文件的权限
for(int i=10;i>=1;i--)
{
msg.mtype=i;
printf("(client)sent\n");
sprintf(msg.msgtext,"the content of message is: ");
sprintf(string_i,"message %d",i);
strcat(msg.msgtext,string_i); //连接操作
strcat(msg.msgtext,"\n");
msgsnd(msgqid,&msg,1030,0);
}
exit(0);
}
int main()
{
while((i=fork())==-1);
if(!i) SERVER();
while((i=fork())==-1);
if(!i) CLIENT();
wait(0);
wait(0);
}
软中断+消息队列
#include<stdio.h>
#include<sys/types.h>
#include<sys/msg.h>
#include<sys/ipc.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<unistd.h>
#define MSGKEY 75
struct msgfrom{
long mtype;
char msgtext[1030];
}msg;
int msgqid,i;
int n;
void SERVER();
int state;
void CLIENT();
void stop()
{
state=0;
}
void waiting()
{
while(state!=0);
}
int main()
{
while((i=fork())==-1);
if(i>0)
{
SERVER();//父
}
else{
CLIENT(); //子
}
wait(0);
wait(0);
}
void SERVER(){
msgqid=msgget(MSGKEY,0777|IPC_CREAT); //寻找键值=75的消息队列
state=0;
do
{
msgrcv(msgqid,&msg,1030,0,0);
printf("(server)received message %d ",msg.mtype);
printf("%s",msg.msgtext);
kill(n,17);
}while(msg.mtype!=1);
msgctl(msgqid,IPC_RMID,0);
exit(0);
}
void CLIENT()
{
int i;
char string_i[50];
msgqid=msgget(MSGKEY,0777); //新建键值=75的消息队列
for(i=10;i>=1;i--)
{
msg.mtype=i;
printf("(client)sent:Hi!\n");
sprintf(msg.msgtext,": number %d say hi!",i);
strcat(msg.msgtext,"\n");
msgsnd(msgqid,&msg,1030,0);
state=1;
signal(17,stop);
waiting();
}
exit(0);
}