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

简介: Linux进程通信,软中断+消息队列,实现了简单的聊天功能。

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

转眼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);
目录
相关文章
|
4小时前
|
存储 Linux Windows
【操作系统】实验十 设备驱动程序设计
【操作系统】实验十 设备驱动程序设计
4 0
|
4小时前
【操作系统】实验九 写一个设备驱动程序
【操作系统】实验九 写一个设备驱动程序
6 1
|
4小时前
【操作系统】实验八 proc文件系统
【操作系统】实验八 proc文件系统
7 1
|
4小时前
|
Linux API
【操作系统】实验七 显示进程列表
【操作系统】实验七 显示进程列表
8 1
|
4小时前
|
存储 机器学习/深度学习 算法
【操作系统】实验六 分析源代码
【操作系统】实验六 分析源代码
7 1
|
4小时前
|
Linux 编译器 API
【操作系统】实验五 添加内核模块
【操作系统】实验五 添加内核模块
5 1
|
4小时前
|
Linux 开发工具 C语言
【操作系统】实验四 增加Linux系统调用
【操作系统】实验四 增加Linux系统调用
8 1
|
4小时前
|
NoSQL Ubuntu Linux
【操作系统】实验三 编译 Linux 内核
【操作系统】实验三 编译 Linux 内核
5 1
|
4小时前
|
存储 Linux 网络安全
【操作系统】实验二 Proc文件系统
【操作系统】实验二 Proc文件系统
6 1
|
4小时前
|
安全 Linux 网络安全
【操作系统】实验一 Linux操作系统安装
【操作系统】实验一 Linux操作系统安装
9 3

热门文章

最新文章