操作系统实验报告三

操作系统实验报告

姓名:许恺

学号:2014011329

日期:2016.11.22

题目1:设计一段内存结构,能够缓存一定数量的网页,在客户端访问时,首先从内存中查找是否存在客户端访问的网页内容,如果存在,则直接从内存中将相应的内容返回给客户端;如果不存在,则从磁盘中将网页内容读入到内存,并返回给客户端

 

1.思想以及准备怎么做

在刚刚读完题目之后我的想法已经有了一点感觉要怎样做了,因为报告拖了比较久,所以老师也说过很多,好了直奔主题,首先要设计一段内存结构,用来缓存网页,其实就是做几个能放网页源代码的字符串数组的一个数据结构,也就是说开辟了一段内存结构;因为我们在程序中建立的数据结构就是在内存中的,所以就相当于一段内存结构,要是以前一定被这句话吓到不会做了,其实只是建立几个数据结构而已。

而后就是将之前的web实验嫁接到这上面,使其先从现有的内存中找目标网页,没有的话就从磁盘中用文件读写将其读到内存中,显示到客户端,同时时刻将这段内存结构展示到终端上用来监视。

2.源代码

主函数webserver3.cpp:

// webserver3.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include <iostream>
#include <Winsock2.h>
#include <windows.h>
#include <string>
#include <fstream>
#include "PageMemo.h"
PageMemo Mem;    //初始化内存中的网页
SOCKET socketconn;
static string dir = "D:\\xukai\\学习\\操作系统实验\\网页";    //文件路径
#include "Thread.h"
#include "CMyTask.h"
#pragma comment(lib, "ws2_32.lib")
using namespace std;

void main(int argc, _TCHAR* argv[])
{
    CMyTask taskObj;
    CThreadPool threadPool(10);

    //初始化WinSock库
    WORD wVersionRequested;
    WSADATA wsaData;

    cout << "初始化库成功" << endl;

    wVersionRequested = MAKEWORD(2, 2);
    int wsaret = WSAStartup(wVersionRequested, &wsaData);

    if (wsaret)
        return;
    //创建SOCKET
    SOCKET socketSrv;
    socketSrv = socket(AF_INET, SOCK_STREAM, 0);

    if (socketSrv == INVALID_SOCKET)
        return;
    cout << "创建socket成功" << endl;
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(80);

    //绑定套接字
    if (bind(socketSrv, (struct sockaddr*)&addrSrv, sizeof(SOCKADDR)))
    {
        //关闭连接
        shutdown(socketSrv, 1);
        closesocket(socketSrv);
        WSACleanup();
        return;
    }
    cout << "绑定套接字成功!" << endl;
    //等待客户端连接
    SOCKADDR_IN addrCli;
    int len = sizeof(SOCKADDR);
    //监听端口
    if (listen(socketSrv, 5) == SOCKET_ERROR)
    {
        printf("监听失败!\n");
    }

    while (true)
    {
        socketconn = accept(socketSrv, (SOCKADDR*)&addrCli, &len);
        //接受连接
        if (socketconn == SOCKET_ERROR)
        {
            printf("接受连接失败!\n");
            return;
        }
        cout << "连接成功" << endl;
        taskObj.SetData((void*)0);    //将任务内容设到对象里
        threadPool.AddTask(&taskObj);    //将任务对象添加到线程池的任务队列
        CThreadPool::Threadfunction();
    }
    shutdown(socketSrv, 1);
    closesocket(socketSrv);
    //关闭连接

    WSACleanup();
}

多线程Thread.h:
#pragma once
#ifndef __THREAD_H
#define __THREAD_H
#include "PageMemo.h"
#include <vector>
#include <string>
#include <pthread.h>
#pragma comment(lib,"x86/pthreadVC2.lib")
using namespace std;

/**
* 执行任务的类,设置任务数据并执行
*/
class CTask
{
protected:
    string m_strTaskName;  /** 任务的名称 */
    void* m_ptrData;       /** 要执行的任务的具体数据 */
public:
    CTask() {}
    CTask(string taskName)    //任务类的重载:设置任务名,设置任务内容为空
    {
        m_strTaskName = taskName;
        m_ptrData = NULL;
    }
    virtual int Run() = 0;            /*启动任务的虚函数*/
    void SetData(void* data);    /** 设置任务数据 */

public:
    virtual ~CTask() {}    //虚拟析构函数
};

/**
* 线程池管理类的实现
*/
class CThreadPool
{
private:
    static  vector<CTask*> m_vecTaskList;     /** 任务列表 */
    static  bool shutdown;                    /** 线程退出标志 */
    int     m_iThreadNum;                     /** 线程池中启动的线程数 */
    pthread_t   *pthread_id;

    static pthread_mutex_t m_pthreadMutex;    /** 线程同步锁 */
    static pthread_cond_t m_pthreadCond;      /** 线程同步的条件变量 */

protected:
    static int MoveToIdle(pthread_t tid);       /** 线程执行结束后,把自己放入到空闲线程中 */
    static int MoveToBusy(pthread_t tid);       /** 移入到忙碌线程中去 */
    static void* ThreadFunc(void*); /** 新线程的线程回调函数 */
    int Create();          /** 创建线程池中的线程 */

public:
    static void Threadfunction();    //在主函数中调用的任务函数
    CThreadPool(int threadNum = 10);
    int AddTask(CTask *task);      /** 把任务添加到任务队列中 */
    int StopAll();                 /** 使线程池中的线程退出 */
    int getTaskSize();             /** 获取当前任务队列中的任务数 */
};

#endif

多线程Thread.cpp:
#include "stdafx.h"
#include "Thread.h"
#include <iostream>  

void CTask::SetData(void * data)  //设置任务的具体内容
{
    m_ptrData = data;
}

vector<CTask*> CThreadPool::m_vecTaskList;         //任务列表
bool CThreadPool::shutdown = false;            //设置关闭为0

pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER;    //设置变量值
pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;

/**
* 线程池管理类构造函数
*/
CThreadPool::CThreadPool(int threadNum)
{
    this->m_iThreadNum = threadNum;    //用参数设置线程数量
    cout << "I will create " << threadNum << " threads\n" << endl;
    Create();    //调用创建线程的函数
}

/**
* 线程回调函数
*/
void* CThreadPool::ThreadFunc(void*)
{

    return (void*)1;
}

void CThreadPool::Threadfunction()
{
    pthread_t tid = pthread_self();
    printf("tid %lu run\n", tid);
    vector<CTask*>::iterator iter = m_vecTaskList.begin();    //添加迭代器从任务列表开头
                                                            /**
                                                            * 取出一个任务并处理之
                                                            */
    CTask* task = *iter;
    if (iter != m_vecTaskList.end())
    {
        task = *iter;
        m_vecTaskList.erase(iter);
    }
    pthread_mutex_unlock(&m_pthreadMutex);
    task->Run(); /** 执行任务 */
    printf("tid:%lu idle\n", tid);
}
int CThreadPool::MoveToIdle(pthread_t tid)
{
    return 0;
}
int CThreadPool::MoveToBusy(pthread_t tid)
{
    return 0;
}
/**
* 往任务队列里边添加任务并发出线程同步信号
*/
int CThreadPool::AddTask(CTask *task)
{
    pthread_mutex_lock(&m_pthreadMutex);
    this->m_vecTaskList.push_back(task);
    pthread_mutex_unlock(&m_pthreadMutex);
    pthread_cond_signal(&m_pthreadCond);
    return 0;
}
/**
* 创建线程
*/
int CThreadPool::Create()
{
    pthread_id = (pthread_t*)malloc(sizeof(pthread_t) * m_iThreadNum);
    for (int i = 0; i < m_iThreadNum; i++)
    {
        pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL);
    }
    return 0;
}

/**
* 停止所有线程
*/
int CThreadPool::StopAll()
{
    /** 避免重复调用 */
    if (shutdown)
    {
        return -1;
    }
    printf("Now I will end all threads!!\n");
    /** 唤醒所有等待线程,线程池要销毁了 */
    shutdown = true;
    pthread_cond_broadcast(&m_pthreadCond);
    /** 阻塞等待线程退出,否则就成僵尸了 */
    for (int i = 0; i < m_iThreadNum; i++)
    {
        pthread_join(pthread_id[i], NULL);
    }
    free(pthread_id);
    pthread_id = NULL;
    /** 销毁条件变量和互斥体 */
    pthread_mutex_destroy(&m_pthreadMutex);
    pthread_cond_destroy(&m_pthreadCond);
    return 0;
}

/**
* 获取当前队列中任务数
*/
int CThreadPool::getTaskSize()
{
    return m_vecTaskList.size();
}

关键代码 工作代码CMyTask.h:
#pragma once
#include "Thread.h"
#include "windows.h"
#include "PageMemo.h"
class CMyTask : public CTask
{
public:
    CMyTask() {}
    inline int Run()
    {
        printf("Process startup!\n");
        //init
        WORD wVersionRequested;
        WSADATA wsaData;
        wVersionRequested = MAKEWORD(2, 2);
        WSAStartup(wVersionRequested, &wsaData);
        DWORD pid = ::GetCurrentProcessId();

        sockaddr_in sa;
        int add_len = sizeof(sa);
        if (socketconn != INVALID_SOCKET)
        {
            getpeername(socketconn, (struct sockaddr *)&sa, &add_len);
            //while (1)
            //{
            //连接成功后与客户端进行会话
            char recvBuff[10000];
            string sendBuf;
            string locDir;
            ifstream fp;
            //接收请求
            if (recv(socketconn, recvBuff, 10000, 0) == SOCKET_ERROR)
            {
                printf("%d\n", socketconn);
                printf("error!");
                getchar();
                return 0;
            }
            //读取http请求头
            string recvBuffer = recvBuff;
            int posGet = recvBuffer.find("GET", 0);
            int posHttp = recvBuffer.find("HTTP", 0);
            //截取html文件路径
            for (int pos = posGet + 4; pos < posHttp; pos++)
            {
                if (recvBuffer[pos] == ‘/‘)
                {
                    locDir.push_back(‘\\‘);
                    continue;
                }
                locDir.push_back(recvBuffer[pos]);
            }
            locDir = dir + locDir;
            int i;
            //打开http请求文件进行读取
            for ( i= 0; i < 10; i++)    //看看内存里有没有现成的
            {
                //cout << locDir << endl;
                //cout << Mem.getfile(i) << endl;
                if (strcmp(locDir.c_str(),Mem.getfile(i).c_str())==0)    //匹配字符串
                {
                    cout << "在内存中找到相应的页面信息啦!!!" << endl;
                    Mem.plusone(i);    //使用次数+1
                    //cout << Mem.getPage(i) << endl;
                    sendBuf = Mem.getPage(i);
                    break;
                }
            }
            if (i == 10)    //内存中没有,从磁盘中调取
            {
                cout << "555555,/(ㄒoㄒ)/~~还得从磁盘取~~" << endl;
                fp.open(locDir.c_str(), std::ios::binary);
                //打开文件失败
                if (!fp.is_open())
                {
                    cout << "请求文件" << locDir.c_str() << "不存在" << endl;
                }
                else//打开文件成功并读取
                {
                    char buffer[1024];
                    while (fp.good() && !fp.eof())
                    {
                        fp.getline(buffer, 1024);
                        //将读取的内容追加入sendBuf中
                        sendBuf.append(buffer);
                        buffer[0] = ‘\0‘;
                    }
                }
                fp.close();
                int x = Mem.Min();    //找到最不经常用的页
                Mem.writefile(x, locDir);    //把调用的页的路径也放内存里
                Mem.writePage(x,sendBuf);    //把调用的页放到内存里
                Mem.writeUser_f(x,1);        //将使用次数置为一
            }
            Mem.print();
            //响应请求,将页面信息发送到客户端
            cout << sendBuf << endl;
            if (send(socketconn, sendBuf.c_str(), sendBuf.length(), 0) == SOCKET_ERROR)
            {
                return 0;
            }
            shutdown(socketconn, 1);
            //关闭连接
            i = 0;    //重置计数的i
            closesocket(socketconn);
        }
        else
        {
            printf("[%d]fail accept:%d\n", pid, ::WSAGetLastError());
        }
        return 0;
    }
};

关键代码 页面PageMemo.h:
#pragma once
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
/*
    用来放网页的内存结构类
*/
class PageMemo
{
public:
    /*
    ***内存结构构造函数,建立10个页面信息,从磁盘写入内存10个网页信息***
    */
    PageMemo()
    {
        ifstream fp[10];    //用10个文件读的对象
        int i;
        string which = "";
        for (i = 0; i < 10; i++)
        {
            which = to_string(i);
            file[i] = "D:\\xukai\\学习\\操作系统实验\\网页\\" + which + ".html ";
            //cout << file[i] << endl;
            fp[i].open(file[i], std::ios::binary);
            //打开文件失败
            if (!fp[i].is_open())
            {
                cout << "请求文件" << which + ".html" << "不存在" << endl;
            }
            else//打开文件成功并读取
            {
                char buffer[1024];
                while (fp[i].good() && !fp[i].eof())
                {
                    fp[i].getline(buffer, 1024);
                    //cout << buffer << endl;
                    //将读取的内容追加入sendBuf中
                    Page[i].append(buffer);
                    //cout << Page[i] << endl;
                    buffer[0] = ‘\0‘;
                }
            }
            fp[i].close();
        }
    }
    ~PageMemo()
    {
    }
    /*
    ***求出被用过次数最少的内存中的页面,用的最普通的算法***
    */
    int Min()
    {
        int M=User_f[0],X=0;
        for (int i = 1; i < 10; i++)
        {
            if (User_f[i] < M)
            {
                X = i;
                M = User_f[i];
            }
        }
        return X;
    }
    /*
    ***在屏幕上打印当前页面的路径信息和使用次数***
    */
    void print()
    {
        cout << "现在要输出我当前的网页的内存信息:" << endl;
        for (int i = 0; i < 10; i++)
        {
            cout <<"   "<< file[i] << "   " << User_f[i] << endl;
        }
    }
    //得到第i条路径的内容
    string getfile(int i) { return file[i]; }
    //得到第i个页面的内容
    string getPage(int i) { return Page[i]; }
    //得到第i个页面使用次数
    int getUser_f(int i) { return User_f[i]; }
    //使用过一次这个网页了,使用次数+1
    void plusone(int i) { User_f[i]++; }
    //修改file内容函数
    void writefile(int i, string f) { file[i] = f; }
    //修改Page内容函数
    void writePage(int i, string p) { Page[i] = p; }
    //修改User_f值的函数
    void writeUser_f(int i, int n) { User_f[i] = n; }
private:
    string file[10];    //页面路径
    string Page[10];    //页面信息
    int User_f[10] = { 0 };        //使用次数

3.结果贴图

刷新了几次后:

4.结论分析和体会

我通过建立数据结构分配了一部分内存,然后编写代码来区分是直接用内存的还是从磁盘读,这里本来我还想算一下时间做对比,后来懒的做了,因为很明显从磁盘读会更慢一些。在写的过程中,也遇到了一些问题,就是对象声明以及头文件include的顺序以及文件读写上的问题,算是一个复习吧,其中涨了新知识的就是ifstream文件是不能重复使用的,因为文件流的状态会保存,必须clear,最后我还是没有用,因为感觉太费时间了,就直接开辟了10个ifstream对象。

总的来说这次实验相比前几次简单了不少,可能是懂的越来越多,这些也就变的简单了吧,web系列的报告真的是越做越顺利,我学习我快乐~~

 

三.查阅的相关文献和资料 

1.http://bbs.csdn.net/topics/300212983 复习文件读写的头文件

2.https://zhidao.baidu.com/question/175523140.html ifstream文件指针的操作

3.http://blog.csdn.net/learnhard/article/details/5636624 ifstream对象可否打开不同的文件

时间: 02-25

操作系统实验报告三的相关文章

操作系统实验报告四

操作系统实验4 题目1:编写页面内存的LRU替换算法 在实验3基础上考虑,如果当前分配的内存或保存页面的数据项已经被用完,这时再有新的网页请求,需要对已在内存中的网页数据进行替换,本实验内容需要使用LRU算法来对内存中的网页数据进行替换 题目2:编写页面内存的LFU替换算法 实现LFU(最少访问频率的页面替换)算法来管理内存页面 实验报告要求: 实验报告封面如下页所示. 按照题目要求,完成相关实验题目. 2.1报告中要包含完成此题目所查阅的一些关键技术材料.例如内存结构的设计.分配管理.回收方法

20135231 JAVA实验报告三:敏捷开发与XP实践

---恢复内容开始--- JAVA实验报告三:敏捷开发与XP实践 20135231 何佳 实验内容 1. XP基础 2. XP核心实践 3. 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2.完成实验.撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等).解决办法(空洞的方法如“查网络”.“问同学”.“看书”等一律得0分)以及分析(从中

操作系统实验报告二

  操作系统实验报告二 姓名:许恺 学号:2014011329 日期:10月14日 题目1:编写线程池 关键代码如下: 1.Thread.h #pragma once #ifndef __THREAD_H #define __THREAD_H #include <vector> #include <string> #include <pthread.h> #pragma comment(lib,"x86/pthreadVC2.lib") using

第五周总结&amp;实验报告三

第五周总结&实验报告三 实验报告 1.已知字符串:"this is a test of java".按要求执行以下操作:(要求源代码.结果截图.) ① 统计该字符串中字母s出现的次数. ② 统计该字符串中子串"is"出现的次数. ③ 统计该字符串中单词"is"出现的次数. ④ 实现该字符串的倒序输出. ① 统计该字符串中字母s出现的次数. package test3; public class Zifu { public static v

java实验报告三

实验三 敏捷开发与XP实践 一.实验内容 1. XP基础 2. XP核心实践 3. 相关工具 二.实验步骤 (一)敏捷开发与XP 软件工程是把系统的.有序的.可量化的方法应用到软件的开发.运营和维护上的过程.软件工程包括下列领域:软件需求分析.软件设计.软件构建.软件测试和软件维护. 人们在开发.运营.维护软件的过程中有很多技术.做法.习惯和思想体系.软件工程把这些相关的技术和过程统一到一个体系中,叫“软件开发流程”.软件开发流程的目的是为了提高软件开发.运营.维护的效率,并提高软件的质量.用户

JAVA实验报告三:敏捷开发与XP实践

实验内容 1. XP基础 2. XP核心实践 3. 相关工具 实验步骤 (一)敏捷开发与XP 软件工程是把系统的.有序的.可量化的方法应用到软件的开发.运营和维护上的过程.软件工程包括下列领域:软件需求分析.软件设计.软件构建.软件测试和软件维护. 人们在开发.运营.维护软件的过程中有很多技术.做法.习惯和思想体系.软件工程把这些相关的技术和过程统一到一个体系中,叫“软件开发流程”.软件开发流程的目的是为了提高软件开发.运营.维护的效率,并提高软件的质量.用户满意度.可靠性和软件的可维护性. 光

实验报告 三

中国人民公安大学 Chinese people' public security university 网络对抗技术 实验报告   实验三 密码破解技术     学生姓名 张金良 年级 15 区队 1 指导教师 高见     信息技术与网络安全学院 2016年11月7日 实验任务总纲 2016-2017 学年 第 一 学期 一.实验目的 1.加深并消化本课程授课内容,复习所学过的互联网搜索技巧.方法和技术: 2.了解并熟悉常用加密算法.加解密工具.破解工具等互联网资源,对给定的密文.加密文件.系

实验报告三

中国人民公安大学 Chinese people' public security university 网络对抗技术 实验报告   实验三 密码破解技术     学生姓名 张九齐 年级 2015 区队 5 指导教师 高见     信息技术与网络安全学院 2016年11月7日   实验任务总纲 2016-2017 学年 第 一 学期 一.实验目的 1.加深并消化本课程授课内容,复习所学过的互联网搜索技巧.方法和技术: 2.了解并熟悉常用加密算法.加解密工具.破解工具等互联网资源,对给定的密文.加密

C语言程序设计实验报告三

C程序设计实验报告 姓 名:赖瑾 实验地点:家 实验时间:2020年3月25日 实验项目:4.3.1 If语句的应用 4.3.2 switch-case的应用 4.3.3 switch-case嵌套if语句的应用 4.3.4 switch-case结构嵌套的应用 4.3.5 分析程序 计算器的实现 一.实验目的与要求 1.掌握C语言逻辑值的表示方法(0代表"假",1代表"真"). 2.学会正确地使用关系表达式和逻辑表达式. 3.掌握各种形式的if语句语法和使用方法,