操作系统实验:软中断+消息队列

不知道这一年是我感觉过的快,还是大家都觉得过的快。

转眼2018年就要过去了,很长一段时间(大概三四个月)没有写博客了,随着学的东西越来越多,也越来越觉得自己是那么的无知。也就不知道该怎么下笔才好,昨天晚上肝完了操作系统实验作业,准备也写一篇博客。

现在,要开始准备明年的春招了,博客也会开始慢慢更新。

操作系统实验报告

一、 实验名称:Linux进程通信

二、 实验目的:掌握Linux进程通信的各种方式

三、 实验内容:软中断+消息队列

四、 程序清单

客户端:

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include<sys/shm.h>

#include<signal.h>

#define MSG_SIZE 128
int wait_mark;

int waiting()
{
    while(wait_mark != 0);
}

void stop()
{
    wait_mark = 0;
}

struct msgbuf

{

    long mtype;

    char mtext[MSG_SIZE];

};

int main()

{
    int senderPid = -1;
    int qid;

    key_t key;

    int ret;

    struct msgbuf buf;
    /*
    函数ftok把一个已存在的路径名和一个整数标识得转换成一个key_t值,称为IPC键
    */
    key=ftok("/home/oswork", 'jzzzz');  //可以自定义,这里调用ftok函数生成消息队列的键值

    if (key<0)

    {

        perror("ftok error");

        exit(1);

    }

    qid=msgget(key, IPC_CREAT|0666);

    if (qid<0)

    {

        perror("msgget error");

        exit(1);

    }
    int flag = 1;
    while (1)

    {
        if(flag == 1)
        {
            flag = 0;
            printf("input the message:");

            fgets(buf.mtext,MSG_SIZE,stdin);

            if (strncmp(buf.mtext, "exit",4)==0)

            {

                buf.mtype=getpid();

                ret=msgsnd(qid, &buf, MSG_SIZE, 0);
                msgctl(qid, IPC_RMID,0);

                break;

            }

            buf.mtype=getpid();

            ret=msgsnd(qid, &buf, MSG_SIZE, 0);

            if (ret<0)

            {

                perror("msgsnd error");

                exit(1);

            }

            else

            {

                printf("send!\n");

            }
            wait_mark = 1;
            signal(17, stop);
            waiting();
        }
        else
        {
            flag = 1;
            memset(&buf, 0, sizeof(buf));

            if(senderPid == -1)
            {
                ret=msgrcv(qid, &buf, MSG_SIZE, 0, 0);
            }
            else
            {
                ret=msgrcv(qid, &buf, MSG_SIZE, senderPid, 0);
            }

            if(senderPid == -1)
            {
                senderPid = buf.mtype;
            }
            wait_mark = 1;

            if (ret<0)

            {

                perror("msgrcv error");

                exit(1);

            }

            else

            {

                if (strncmp(buf.mtext, "exit",4)==0)

                {
                    msgctl(qid, IPC_RMID,0);
                    break;

                }

                printf("received message:\n");

                printf("text:%s\n",buf.mtext);

                kill(senderPid, 17);
            }
        }

    }

    return 0;

}

服务端:

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include<sys/shm.h>

#include<signal.h>

#define MSG_SIZE 128

int wait_mark;
int qid;

int waiting()
{
    while(wait_mark != 0);
}

void stop()
{
    wait_mark = 0;
}

void sig_handler()
{
    msgctl(qid, IPC_RMID,0);
}

struct msgbuf

{

    long mtype;

    char mtext[MSG_SIZE];

};

int main()

{
    int senderPid = -1;

    int recPid = -1;

    key_t key;

    int ret;

    struct msgbuf buf;

    key=ftok("/home/oswork", 'jzzzz');

    if (key<0)

    {

        printf("ftok error");

        exit(1);

    }

    qid=msgget(key,IPC_EXCL|0666);

    if (qid<0)

    {

        perror("msgget error");

        exit(1);

    }
    int flag = 0;

    while (1)

    {
        if(flag == 0)
        {
            flag = 1;
            memset(&buf, 0, sizeof(buf));
            if(senderPid == -1)
            {
                ret=msgrcv(qid, &buf, MSG_SIZE, 0, 0);
            }
            else
            {
                ret=msgrcv(qid, &buf, MSG_SIZE, senderPid, 0);
            }

            if(senderPid == -1)
            {
                senderPid = buf.mtype;
            }
            wait_mark = 1;

            if (ret<0)

            {

                perror("msgrcv error");

                exit(1);

            }

            else

            {

                if (strncmp(buf.mtext, "exit",4)==0)

                {

                    break;

                }

                printf("received message:\n");

                printf("text:%s\n",buf.mtext);

                kill(senderPid, 17);
            }
        }
        else
        {
            flag = 0;
            printf("input the message:");
            signal(SIGINT, sig_handler);

            fgets(buf.mtext,MSG_SIZE,stdin);

            if (strncmp(buf.mtext, "exit",4)==0)

            {
                buf.mtype=getpid();

                ret=msgsnd(qid, &buf, MSG_SIZE, 0);

                break;

            }

            buf.mtype=getpid();

            ret=msgsnd(qid, &buf, MSG_SIZE, 0);

            if (ret<0)

            {

                perror("msgsnd error");

                exit(1);

            }

            else

            {

                printf("send!\n");

            }
            wait_mark = 1;
            signal(17, stop);
            waiting();
        }

    }

    return  0;

}

五、 程序测试

此处输入图片的描述

六、 实验总结

最后,选择了“软中断+消息队列”的方式来实现了一个简单的聊天工具。
可以实现两人的在线聊天:

  1. 一人一句,不能争抢,这个机制是通过软中断信号处理来实现的,kill向指定进程发送信号,signal接受信号并进行相应的处理。
  2. 两人间对话消息的传递是通过消息队列实现的,选择消息队列而没有用管道通信是因为管道通信是按FIFO的方式单向传递的,而且只允许在建立者和子进程间使用。消息队列允许一个或多个进程向它读写消息,而且允许随机读取(按消息的类型读取,比如我程序中将消息队列标识符id就设置成了等于进程标识符pid),不是FIFO。
  3. 功能:
    a) 有两个会话A,B,

b) 一开始会话A处于等待键盘输入发送给B消息的状态,会话B处于等待接受A的发送消息的状态。
c) 键盘输入消息,A成功发送,A的状态变为等待接受B的消息,B成功接受,B的状态变为等待键盘输入文字发送给A消息。
d) 重复b,c环节
e) 直到一方输入”exit”字符串,双方同时结束会话,并且清空消息队列。

在实验中也遇到了一些问题,其中比较麻烦的是:
在我写好代码调试运行的时候,因为一方A是发送端,另一方B肯定是接受端,但一开始两边程序刚开始运行的时候,在键盘还没有输入任何字符时,接收端B会莫名其妙的“收到消息”!!!
但这个消息又不是A发送过来的,那就造成了B不能给A发送信号,告诉它“我已经收到了你的消息”,所以A还是处于等待键盘输入发送消息的状态。但此时B因为收到了消息,已经变成了等待键盘输入发送消息的状态。这样就造成了A在等B接受到消息而发送回信号,同时B也在等A接受到消息而发送回信号。但此时因为两边都是等待键盘输入准备发送消息的状态,而没有接受消息的一端,无论在A、B哪一端发消息,另一端都不会收到,僵持的状态也不会改变。
这样就造成了死锁。
重新检查了一遍代码,发现了问题出在了我没有在每次会话结束后,把消息队列清空。
于是,我在两个地方增加了清空消息队列的代码:
1. 会话正常结束,即我在程序中写的通过发送“exit”字符串的方式主动结束会话,在结束之前调用了msgctl(qid, IPC_RMID,0);来清除队列中的消息

            if (strncmp(buf.mtext, "exit",4)==0)

            {

                buf.mtype=getpid();

                ret=msgsnd(qid, &buf, MSG_SIZE, 0);
                msgctl(qid, IPC_RMID,0);

                break;

            }

2. 会话强制结束,即键盘按下Ctrl + C结束会话。通过软中断来实现。

void sig_handler()
{
    msgctl(qid, IPC_RMID,0);
}

signal(SIGINT, sig_handler);
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值