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

简介: 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 Shell 调度
操作系统实验一:进程和线程(1)
实验内容 一、进程的创建 编写一段源程序,使用系统调用fork()创建子进程,当此程序运行时,在系统中有父进程和子进程在并发执行。观察屏幕上的显示结果,并分析原因(源代码:forkpid.c)。
87 0
|
5月前
|
存储 算法 调度
操作系统实验五:存储管理设计
操作系统实验五:存储管理设计
155 0
|
6月前
|
存储 Linux C语言
【操作系统】实验一 Linux初步
【操作系统】实验一 Linux初步
110 0
【操作系统】实验一 Linux初步
|
4月前
|
调度 数据库
操作系统实验一:进程和线程(2)
七、共享资源的互斥访问 创建两个线程来实现对一个数的递加 pthread_example.c 1、运行
39 0
|
5月前
|
存储 缓存 前端开发
操作系统期末实验:多用户二级文件系统
操作系统期末实验:多用户二级文件系统
230 0
|
5月前
|
存储 算法 搜索推荐
操作系统实验四:进程调度
操作系统实验四:进程调度
84 0
|
5月前
|
存储 算法 安全
操作系统实验三:死锁避免程序设计
操作系统实验三:死锁避免程序设计
67 0
|
5月前
|
存储 前端开发 Linux
操作系统实验一:时钟中断程序设计
操作系统实验一:时钟中断程序设计
80 0
|
5月前
|
数据可视化 Python
操作系统实验二:进程同步程序设计
操作系统实验二:进程同步程序设计
141 0
|
7月前
|
机器学习/深度学习 Ubuntu 算法
操作系统原理实验2:进程调度(在Ubuntu虚拟机gcc编译环境下
操作系统原理实验2:进程调度(在Ubuntu虚拟机gcc编译环境下
100 0