【操作系统实验】软中断+客户端服务器实现消息的一发一收


一.题目名称
实现客户端与服务器端之间消息的一发一收
二.问题描述
实现客户端与服务器端之间消息的一发一收

软中断:

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);
}

                      

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值