操作系统实验报告二

2019-11-30 14:24 来源:未知

动态分区存储管理方式主存的分配与回收

16网络工程二班 孙书魁

 

 

 

 

 

 

操作系统实验报告二

 

 

 

                       姓名:许恺

                       学号: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 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 void* ThreadFunc(void * threadData); /** 新线程的线程回调函数 */
    static int MoveToIdle(pthread_t tid);       /** 线程执行结束后,把自己放入到空闲线程中 */
    static int MoveToBusy(pthread_t tid);       /** 移入到忙碌线程中去 */

    int Create();          /** 创建线程池中的线程 */

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

#endif
2.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 << " threadsn" << endl;
    Create();    //调用创建线程的函数
}

/**
* 线程回调函数
*/
void* CThreadPool::ThreadFunc(void* threadData)
{
    pthread_t tid = pthread_self();        
    while (1)
    {
        pthread_mutex_lock(&m_pthreadMutex);
        while (m_vecTaskList.size() == 0 && !shutdown)    //没有任务就挂起等待
        {
            pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);
        }

        if (shutdown)    //如果是关闭的就解锁退出线程
        {
            pthread_mutex_unlock(&m_pthreadMutex);
            printf("thread %lu will exitn", pthread_self());
            pthread_exit(NULL);
        }

        printf("tid %lu runn", 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 idlen", tid);
    }
    return (void*)0;
}

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

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

#include "stdafx.h"
#include "Thread.h"  
#include <iostream>  
#include <windows.h>

class CMyTask : public CTask
{
public:
    CMyTask() {}

    inline int Run()
    {
        printf("%sn", (char*)this->m_ptrData);
        Sleep(10);
        return 0;
    }
};

int main()
{
    CMyTask taskObj;

    char szTmp[] = "this is the first thread runningn";  //任务内容
    taskObj.SetData((void*)szTmp);    //将任务内容设到对象里
    CThreadPool threadPool(10);

    for (int i = 0; i < 20; i  )
    {
            threadPool.AddTask(&taskObj);    //将任务对象添加到线程池的任务队列
    }

    while (1)//检查任务完成情况,看是否退出
    {
        printf("there are still %d tasks need to handlen", threadPool.getTaskSize());
        if (threadPool.getTaskSize() == 0)
        {
            if (threadPool.StopAll() == -1)    //如果没剩就退出
            {
                printf("Now I will exit from mainn");
                exit(0);
            }
        }
        Sleep(10);    //给予任务执行时间
    } 

    return 0;
}

 

 

 

操作系统实验4

 

题目2:将Web服务器接收功能加入到此线程池中,让线程池中的线程完成信号接收功能、文件读取和发送

程序代码以及运行贴图:

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

#include "stdafx.h"
#include <iostream>  
#include <Winsock2.h> 
#include <windows.h>
#include <string>
#include <fstream>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
SOCKET socketconn;
static string dir = "D:\xukai\学习\操作系统实验\webServer1\webServer\Debug\";//文件路径
#include "Thread.h"  
#include "CMyTask.h"
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();
}

2.Thread.h
#pragma once
#ifndef __THREAD_H  
#define __THREAD_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
3.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 << " threadsn" << endl;
    Create();    //调用创建线程的函数
}

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

    return (void*)1;
}

void CThreadPool::Threadfunction()
{
    pthread_t tid = pthread_self();
    printf("tid %lu runn", 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 idlen", 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();
}

4.CMyTask.h
#pragma once
#include "Thread.h"
#include "windows.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("%dn", 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;
            //打开http请求文件进行读取
            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();
            //响应请求,将页面信息发送到客户端
            if (send(socketconn, sendBuf.c_str(), sendBuf.length(), 0) == SOCKET_ERROR)
            {
                return 0;
            }
            shutdown(socketconn, 1);
            //关闭连接
            closesocket(socketconn);
        }
        else
        {
            printf("[%d]fail accept:%dn", pid, ::WSAGetLastError());
        }
        return 0;
    }
};

伟德国际官网注册平台 1

伟德国际官网注册平台 2

 

 

题目1:编写页面内存的LRU替换算法

在实验3基础上考虑,如果当前分配的内存或保存页面的数据项已经被用完,这时再有新的网页请求,需要对已在内存中的网页数据进行替换,本实验内容需要使用LRU算法来对内存中的网页数据进行替换

目的:

           1,了解动态分区分配中,使用的数据结构和算法

          2,深入了解动态分区存储管理方式,主存分配与回收的实现

          3,进一步加深动态分区存储管理方式及其实现过程的了解

题目3:Web服务器对所有的Web页面请求进行计数,并能够对每个线程处理页面请求时间计时,每分钟报告一次服务器的状态:状态服务器需打印出当前时间,一共处理了多少请求链接,本分钟处理了多少链接请求,每次链接请求的时间是多少?

 

结论:

  进程的网页测试在实验一的基础上进行,多线程的直接使用了老师给的工具,这里偷了个小懒。经过程序计算,多线程方法显然比进程的要快一些,是因为它不用一遍一遍去创建和释放进程,有线程池循环调用,在互斥锁的功能下也不会出现阻塞。因为不同的程序进行计算时间在细节上会有一定偏差但是差别不大,在这里我们忽略不记。

 

 

结果如图:

进程:

伟德国际官网注册平台 3

 

线程:

 伟德国际官网注册平台 4

 

参考资料如下:

1.线程池代码来源:http://blog.csdn.net/rain_qingtian/article/details/12559073    感谢博主帮助。

2.在Windows下的pthread.h怎么用:

http://blog.csdn.net/qianchenglenger/article/details/16907821  

3.还有修改阅读过的N个线程池代码:

http://www.oschina.net/code/snippet_256947_46521

http://blog.csdn.net/ithzhang/article/details/9020283

http://www.jb51.net/article/54827.htm

http://www.cnblogs.com/lidabo/p/3328402.html

......

4.pthread_cond_wait是什么:http://baike.baidu.com/link?url=TntmcKnSMIsUSSn2o_V1F2hEdaCw8UAxIJgkZcjK9StSRLB7MXRfFeZA1TaDnUlSLNUGRhy1xS7x7jlPfzCWiK

5.VS无法打开pdb文件的解决方法:

http://blog.sina.com.cn/s/blog_96d4636a0102vknm.html

6.createthread函数使用方法:

http://www.doc88.com/p-415724533553.html

7._sprintf_s函数使用方法:

http://blog.163.com/ka_ciky/blog/static/1359004362011711102457625/

8.c 下int和char*和string的转换(网上到处都是就不贴网站了)

 

 

题目2:编写页面内存的LFU替换算法

实现LFU(最少访问频率的页面替换)算法来管理内存页面

具体实现:

            确定主存分配表,然后采用最佳适应算法,完成完成主存分配和回收,最后编写主函数,进行主函数进行测试。

 

 

实验报告要求:

  1. 实验报告封面如下页所示。
  2. 按照题目要求,完成相关实验题目。

伟德国际官网注册平台,2.1报告中要包含完成此题目所查阅的一些关键技术材料。例如内存结构的设计、分配管理、回收方法等内容。

2.2 报告中有实现的关键技术点源代码,源代码书写要有一定的规范,源代码中有相关的注释

2.3 作为扩展,在界面上能够定时给出当前内存的占用情况。因此根据上面的题目,可以适当地增加对其它方面的信息监控。

 

 

 

 

 

 

操作系统实验报告四

 

 

 

                       姓名:许恺

                       学号:2014011329

                       日期:12月7日

 

 

 

 

 

 

 

 

 

 

具体实现:

            主存分配之前的之态,主存分配过程中的状态,回收后的状态

 

  1 #include <stdio.h>   
  2 #include <string.h>
  3 #define MAX 600  //设置总内存大小为512k
  4 
  5 struct partition {
  6     char    pn[10];//分区名字
  7     int     begin;//起始地址
  8     int     size;//分区大小 
  9     int     end;//结束地址
 10     char    status;//分区状态
 11  };
 12  struct partition    part[MAX];
 13  int    p = 0; //标记上次扫描结束处 
 14  
 15  void Init()//初始化分区地址、大小以及状态
 16 {
 17     int i;
 18     for ( i = 0; i < MAX; i   )
 19          part[i].status = '-';
 20      strcpy( part[0].pn, "SYSTEM" );
 21      part[0].begin    = 0;
 22      part[0].size    = 100;
 23      part[0].status    = 'u';
 24   
 25      strcpy( part[1].pn, "-----" );
 26      part[1].begin    = 100;
 27      part[1].size    = 100;
 28      part[1].status    = 'f';
 29      strcpy( part[2].pn, "A" );
 30      part[2].begin    = 200;
 31      part[2].size    = 50;
 32      part[2].status    = 'u';
 33      strcpy( part[3].pn, "-----" );
 34      part[3].begin    = 250;
 35      part[3].size    = 50;
 36      part[3].status    = 'f';
 37      strcpy( part[4].pn, "B" );
 38      part[4].begin    = 300;
 39      part[4].size    = 100;
 40      part[4].status    = 'u';
 41      strcpy( part[5].pn, "-----" );
 42      part[5].begin    = 400;
 43      part[5].size    = 200;
 44      part[5].status    = 'f';
 45      for ( i = 0; i < MAX; i   )
 46          part[i].end = part[i].begin   part[i].size-1;
 47  }
 48   
 49 
 50   void Output( int i ) //以行的形式输出结构体的数据
 51  {
 52      printf( "t%s", part[i].pn );
 53      printf( "t%d", part[i].begin );
 54      printf( "t%d", part[i].size );
 55      printf( "t%d", part[i].end );
 56      printf( "t%c", part[i].status );
 57  }
 58  
 59 
 60  void display() //显示分区 
 61  {
 62      int    i;
 63      int    n; //用n来记录分区的个数
 64      printf("n");
 65      printf( "n        已分配分区表Used:" );
 66      printf( "ntNo.tpronametbegintsizetendtstatus" );
 67      printf("n");
 68      n = 1;
 69      for ( i = 0; i < MAX; i   )
 70      {
 71          if ( part[i].status == '-' )
 72              break;
 73          if ( part[i].status == 'u' )
 74          {
 75              printf( "ntNo.%d", n );
 76              Output( i );
 77              n  ;// 记录已分配使用的分区个数
 78          }
 79      }
 80      printf("n");
 81      printf( "n        空闲分区表Free:" );
 82      printf( "ntNo.tpronametbegintsizetendtstatus" );
 83      printf("n");
 84      n = 1;
 85      for ( i = 0; i < MAX; i   )
 86      {
 87          if ( part[i].status == '-' )
 88               break;
 89         if ( part[i].status == 'f' )
 90           {
 91               printf( "ntNo.%d", n );
 92            Output( i );
 93               n  ;  //记录空闲分区的个数
 94           }
 95     }
 96     // printf( "n" );
 97      printf("n");
 98      printf( "n        内存使用情况,按起始址增长的排:" );
 99      //printf( "n        printf sorted by address:" );
100      printf( "ntNo.tpronametbegintsizetendtstatus" );
101      printf("n");
102      n = 1;
103      for ( i = 0; i < MAX; i   )
104      {
105          if ( part[i].status == '-' )
106              break;
107          printf( "ntNo.%d", n );
108          Output( i );
109         n  ;//记录已分配分区以及空闲分区之和的总个数
110     }
111      getch();
112  }
113  
114  void Fit( int a, char workName[], int workSize ) //新作业把一个分区分配成两个分区:已使用分区和空闲分区 
115  {
116      int i;
117      for ( i = MAX; i > a   1; i-- )
118      {
119         //通过逆向遍历,把在a地址后的所有分区往后退一个分区,目的在于增加一个分区
120          if ( part[i - 1].status == '-' )
121              continue;
122          part[i]=part[i-1];
123     }
124      strcpy( part[a   1].pn, "-----" );
125      part[a   1].begin    = part[a].begin   workSize;
126      part[a   1].size    = part[a].size - workSize;
127      part[a   1].end        = part[a].end-1;
128      part[a   1].status    = 'f';
129     strcpy( part[a].pn, workName );
130      part[a].size    = workSize;
131      part[a].end    = part[a].begin   part[a].size-1;
132      part[a].status    = 'u';
133  }
134  void fenpei() // 分配 
135  {
136      int    i;
137      int    a;
138     int    workSize;
139      char    workName[10];
140      int    pFree;
141      printf( "n请输入作业名称:" );
142      scanf( "%s", &workName );
143      for(i=0;i<MAX;i  )
144     {
145          if(!strcmp(part[i].pn,workName))//判断作业名称是否已经存在
146          {
147              printf("n作业已经存在,不必再次分配!n");
148             return;
149          }
150      }
151      printf( "请输入作业大小(k):" );
152      scanf( "%d", &workSize );
153      for ( i = 0; i < MAX; i   )//通过循环在空闲区找是否有适合区间存储作业
154      {
155          if ( part[i].status == 'f' && part[i].size >= workSize )
156          {
157              pFree = i;
158              break;
159          }
160     }
161     if ( i == MAX )
162     {
163          printf( "n该作业大小超出最大可分配空间" );
164          getch();
165          return;
166      }
167      
168          for ( i = 0; i < MAX; i   )//最佳适应算法
169             if ( part[i].status == 'f' && part[i].size >= workSize )
170                  if ( part[pFree].size > part[i].size )
171                      pFree = i;//通过遍历所有区间,每次都找到最小空闲分区进行分配
172          Fit( pFree, workName, workSize );
173     printf( "n分配成功!" );
174     getch();
175  }
176  void hebing() //合并连续的空闲分区 
177  {
178     int i = 0;
179     while ( i != MAX - 1 )
180     {
181         for ( i = 0; i < MAX - 1; i   )
182         {
183             if ( part[i].status == 'f' )
184                  if ( part[i   1].status == 'f' )
185                 {
186                      part[i].size    = part[i].size   part[i   1].size;
187                      part[i].end    = part[i].begin   part[i].size-1;
188                      i  ;
189                      for ( i; i < MAX - 1; i   )
190                     {
191                         if ( part[i   1].status == '-' )
192                         {
193                             part[i].status = '-';
194                             break;
195   
196                         }
197                         
198                         part[i]=part[i 1];
199                     }
200                      part[MAX - 1].status = '-';
201                      break;
202                  }
203         }
204     }
205  }
206  
207  
208  void huishou() // 回收分区 
209  {
210      int    i;
211      int    number;
212      int    n=0;
213      printf( "n请输入回收的分区号:" );
214      scanf( "%d", &number );
215      if ( number == 1 )
216      {
217          printf( "n系统分区无法回收" );
218          return;
219      }
220      for ( i = 0; i < MAX; i   )//通过循环查找要回收的已使用分区区号
221      {
222          if ( part[i].status == 'u' )
223          {
224              n  ;
225              if ( n == number )
226             {
227                  strcpy( part[i].pn, "-----" );
228                  part[i].status = 'f';
229             }
230          }
231      }
232      if ( i == MAX - 1 )
233      {
234          printf( "n找不到分区" );
235          return;
236      }
237      hebing();//合并连续的空闲分区
238      printf( "n回收成功!" );
239      getch();
240  }
241  
242  
243  void main()
244 {
245      int selection;
246      Init();
247      printf( "初始化完成,设内存容量%dk", MAX );
248      printf( "n系统文件从低址存储,占%dk", part[0].size );
249      while ( 1 )
250      {
251          printf( "n----------选择----------" );
252          printf( "n|  0、退出系统         |" );
253          printf( "n|  1、显示分区         |" );
254          printf( "n|  2、分配分区         |" );
255          printf( "n|  3、回收分区         |" );
256          printf( "n------------------------");
257         printf( "n请选择 > " );
258          while ( 1 )
259          {
260              scanf( "%d", &selection );
261              if ( selection == 0 ||selection == 1 || selection == 2 || selection == 3 )
262                  break;
263              printf( "输入错误,请重新输入:" );
264          }
265          switch ( selection )
266          {
267            case 0:
268            exit(0); //退出系统
269              break;
270          case 1:
271              display(); //显示分区
272              break;
273         case 2:
274              fenpei(); //分配作业
275              break;
276          case 3:
277              huishou();  //回收分区
278              break;
279          default:
280              break;
281          }
282      }
283  }

 

伟德国际官网注册平台 5

伟德国际官网注册平台 6

伟德国际官网注册平台 7

伟德国际官网注册平台 8

 

 

一.构思想法

操作系统实验报告三

操作系统实验报告一

题目1:编写页面内存的LRU替换算法

因为web4和3太像了,所以并没有什么难度,我只需要将替换的页面改一下就可以了,所以我加了一个属性,就是这个页面是第几个被申请的,这样既可以记录网页申请的流量,也可以将在内存中的数字最小的那个替换掉,也就是LRU算法所讲的最久未被用的那个,然后加上时间函数计算出每次用的时间进行分析报告就可以了。

 

 

题目2:编写页面内存的LFU替换算法

其实我想说我web3用的就是LFU替换算法,老师可以看我的web3报告,或者这份报告也可以,这份报告会给出对于一串申请序列,两种方法比较的时间分析。

 

 

 

二.源代码以及结果贴图和分析

 

 

题目1:编写页面内存的LRU替换算法

关键代码(有修改):

Webserver4.cpp:
// webserver4.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\学习\操作系统实验\网页";    //文件路径
int num = 1; //请求网页次数
#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);
    double alltime=0;//运行总时间
    LARGE_INTEGER  large_interger;
    double dff;
    __int64  c1, c2;
    QueryPerformanceFrequency(&large_interger);
    dff = large_interger.QuadPart;
    QueryPerformanceCounter(&large_interger);
    //初始化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;
        //用QueryPerformanceCounter()来计时  微秒  

        c1 = large_interger.QuadPart;
        taskObj.SetData((void*)0);    //将任务内容设到对象里
        threadPool.AddTask(&taskObj);    //将任务对象添加到线程池的任务队列
        CThreadPool::Threadfunction();
        QueryPerformanceCounter(&large_interger);
        c2 = large_interger.QuadPart;
        alltime = alltime   (c2 - c1) / dff;
        printf("本次用时%lf微秒n", (c2 - c1) / dff);
        cout << "到现在为止共用时间:" << alltime << "微秒。" << endl;
        num  ;
    }
    shutdown(socketSrv, 1);
    closesocket(socketSrv);
    //关闭连接

    WSACleanup();
}

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()
    {
    }
    /*
    ****LRU算法的函数,找出前面最久未使用的页面替换
    */
    int LRU()
    {
        int M = lru[0], X = 0;
        for (int i = 1; i < 10; i  )    
        {
            if (lru[i] < M)
            {
                X = i;
                M = lru[i];
            }

        }
        return X;
    }
    /*
    ***求出被用过次数最少的内存中的页面,用的最普通的算法***
    */
    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]<<"    "<<lru[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; }
    //当网页被使用,修改他的lru    
    void writelru(int i, int n) { lru[i] = n; }
private:
    string file[10];    //页面路径
    string Page[10];    //页面信息
    int User_f[10] = { 0 };        //使用次数
    int lru[10] = { 0 };    //此网页第几个被使用,最小的就是最久没被用的
};

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("%dn", 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();    //找到最不经常用的页
                int x = Mem.LRU();    //找到LRU算法的结果
                Mem.writefile(x, locDir);    //把调用的页的路径也放内存里
                Mem.writePage(x, sendBuf);    //把调用的页放到内存里
                Mem.writeUser_f(x, 1);        //将使用次数置为一
                Mem.writelru(x, num);
            }
            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:%dn", pid, ::WSAGetLastError());
        }
        return 0;
    }
};

线程池(未修改):
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 << " threadsn" << endl;
    Create();    //调用创建线程的函数
}

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

    return (void*)1;
}

void CThreadPool::Threadfunction()
{
    pthread_t tid = pthread_self();
    printf("tid %lu runn", 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 idlen", 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();
}

 

 

结果贴图:(因为我有10个内存页面,当我输入,第0,1,2,3,4,5,6,7,8,9,2,23,5,54,4,456,3,2,4,4356,9个页面时的结果,LRU)

0,

伟德国际官网注册平台 9

 

9,

伟德国际官网注册平台 10

23,

伟德国际官网注册平台 11

 

54,

伟德国际官网注册平台 12

 

2,

伟德国际官网注册平台 13

 

456,

伟德国际官网注册平台 14

 

3,

伟德国际官网注册平台 15

 

4356,

伟德国际官网注册平台 16

 

3,

伟德国际官网注册平台 17

 

分析:我们发现从外存调入的大概会用到0.08微秒以上,而从内存中直接用的用时在0.07微秒左右或以下,可看出从内存中是快的,当然可能也跟文件的大小有关系,但是不影响大局。

 

 

LFU算法:

0,

伟德国际官网注册平台 18

 

9,

伟德国际官网注册平台 19

 

23,

伟德国际官网注册平台 20

 

54,

伟德国际官网注册平台 21

 

2,

伟德国际官网注册平台 22

 

456,

伟德国际官网注册平台 23

 

3,

伟德国际官网注册平台 24

 

4356,

伟德国际官网注册平台 25

 

3,

 伟德国际官网注册平台 26

 

分析:LFU的算法时间就很明显了,从外存拿的用时0.1微秒多,而从内存拿的只用了0.04微秒左右,总时间用了1.41638微秒,而LRU算法用了1.17903微秒,在这个序列上LRU算法要比LFU算法要快一些,虽然只实验了一个序列,但是大部分序列LRU算法都是较好的一种算法。

                       姓名:许恺

                       姓名:许恺

三.查阅的文献

1. 时间函数集锦

                       学号:2014011329

                       学号:2014011329

四.体会感想

其实没什么感想,因为和web3一样,而且有很多同学web3就把这个做了,恩,就这样,没什么难度,时间函数也是一查就有。没了。

                       日期:2016.11.22

                       日期:9月29日

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

题目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 << " threadsn" << endl;
    Create();    //调用创建线程的函数
}

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

    return (void*)1;
}

void CThreadPool::Threadfunction()
{
    pthread_t tid = pthread_self();
    printf("tid %lu runn", 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 idlen", 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("%dn", 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:%dn", 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.结果贴图

 伟德国际官网注册平台 27

伟德国际官网注册平台 28

伟德国际官网注册平台 29

伟德国际官网注册平台 30

 

 

刷新了几次后:

 伟德国际官网注册平台 31伟德国际官网注册平台 32

伟德国际官网注册平台 33

伟德国际官网注册平台 34

伟德国际官网注册平台 35

 

 

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对象可否打开不同的文件

 

一.相关技术资料——》

Socket:

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

绑定

函数原型:

int bind(SOCKET socket, const struct sockaddr* address, socklen_t address_len);

参数说明:

socket:是一个套接字描述符。

address:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号。

address_len:确定address缓冲区的长度。

返回值:

如果函数执行成功,返回值为0,否则为SOCKET_ERROR。

接收

函数原型:

int recv(SOCKET socket, char FAR* buf, int len, int flags);

参数说明:*   ***

socket:一个标识已连接套接口的描述字。

buf:用于接收数据的缓冲区。

len:缓冲区长度。

flags:指定调用方式。取值:MSG_PEEK 查看当前数据,数据将被复制到缓冲区中,但并不从输入队列中删除;MSG_OOB 处理带外数据。

返回值:

若无错误发生,recv()返回读入的字节数。如果连接已中止,返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。

创建进程,以及传递socket参数

 bool bRet=::CreateProcess(
  NULL,
  szCommandLine,
  NULL,
  NULL,
  FALSE,
  CREATE_NEW_CONSOLE,
  NULL,
  NULL,
  &si,
  &pi);
 if(bRet)
 {
  ::CloseHandle(pi.hThread);
  ::CloseHandle(pi.hProcess);

1.函数说明:

WIN32API函数CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件。

2.函数原型:
BOOL CreateProcess
(
    LPCTSTR lpApplicationName,        
    LPTSTR lpCommandLine,        
    LPSECURITY_ATTRIBUTES lpProcessAttributes。
    LPSECURITY_ATTRIBUTES lpThreadAttributes,        
    BOOL bInheritHandles,        
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,        
    LPCTSTR lpCurrentDirectory,        
    LPSTARTUPINFO lpStartupInfo,        
    LPPROCESS_INFORMATION lpProcessInformation 
);
3. 参数:

lpApplicationName:

指向一个NULL结尾的、用来指定可执行模块的字符串。

     这个字符串可以使可执行模块的绝对路径,也可以是相对路径,在后一种情况下,函数使用当前驱动器和目录建立可执行模块的路径。
    这个参数可以被设为NULL,在这种情况下,可执行模块的名字必须处于 lpCommandLine 参数的最前面并由空格符与后面的字符分开。
    这个被指定的模块可以是一个Win32应用程序。如果适当的子系统在当前计算机上可用的话,它也可以是其他类型的模块(如MS-DOS 或OS/2)。

 在Windows NT中,如果可执行模块是一个16位的应用程序,那么这个参数应该被设置为NULL,并且因该在lpCommandLine参数中指定可执行模块的名称。16位的应用程序是以DOS虚拟机或Win32上的Windows(WOW) 为进程的方式运行。

lpCommandLine:

指向一个NULL结尾的、用来指定要运行的命令行。

 这个参数可以为空,那么函数将使用参数指定的字符串当作要运行的程序的命令行。

 如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行。新运行的进程可以使用GetCommandLine函数获得整个命令行。C语言程序可以使用argc和argv参数。

如果lpApplicationName参数为空,那么这个字符串中的第一个被空格分隔的要素指定可执行模块名。如果文件名不包含扩展名,那么.exe将被假定为默认的扩展名。如果文件名以一个点(.)结尾且没有扩展名,或文件名中包含路径,.exe将不会被加到后面。如果文件名中不包含路径,Windows将按照如下顺序寻找这个可执行文件:
1.当前应用程序的目录。
2.父进程的目录。

  1. Windows目录。可以使用GetWindowsDirectory函数获得这个目录。
     4.列在PATH环境变量中的目录。
         如果被创建的进程是一个以MS-DOS或16位Windows为基础的应用程序,lpCommandLine参数应该是一个以可执行文件的文件名作为第一个要素的绝对路径,因为这样做可以使32位Windows程序工作的很好,这样设置lpCommandLine参数是最强壮的。

传参

 伟德国际官网注册平台 36

接收

 伟德国际官网注册平台 37

二.报告内容

 

  1. 阅读源代码,并调试,使得在自己本地机上能够显示出网页信息

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

    #include "stdafx.h"

#include <iostream>
#include <fstream>
#include <stdio.h> 
#include <Winsock2.h> 
#include <string>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
//文件路径
static string dir = "D:\xukai\学习\操作系统实验\webServer1\webServer\Debug";
void main(int argc, _TCHAR* argv[])
{
    //初始化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);
以上为创建socket包,定义参数
    //绑定套接字
    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)
    {
        SOCKET socketconn;
        socketconn = accept(socketSrv, (SOCKADDR*)&addrCli, &len);
        //接受连接
客户端反应,服务端接收
        if (socketconn == SOCKET_ERROR)
        {
            printf("接受连接失败!n");
            return;
        }
        cout << "连接成功" << endl;
        /*    while(true)
        {*/

        //连接成功后与客户端进行会话
        char recvBuff[1024];
        string sendBuff;
        string locDir;
        ifstream fp;

        //接收请求
        if (recv(socketconn, recvBuff, 1024, 0) == SOCKET_ERROR)
        {
            continue;
        }
请求客户端发出的地址,放到recvBuff
        //读取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;

        //    locDir.insert(0,1,'.');
        //打开http请求文件进行读取
        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);
                //将读取的内容追加入sendBuff中
                sendBuff.append(buffer);
                buffer[0] = '\0';
            }
读文件,将文件写到sendBuff中
        }
        fp.close();
        //响应请求,将页面信息发送到客户端
        if (send(socketconn, sendBuff.c_str(), sendBuff.length(), 0) == SOCKET_ERROR)
        {
            continue;
        }
向客户端发送网页的内容
        shutdown(socketconn, 1);
        //}
        //关闭连接
        closesocket(socketconn);

    }
    //关闭连接
    shutdown(socketSrv, 1);
    closesocket(socketSrv);
    WSACleanup();

    return;
}

 

伟德国际官网注册平台 38

 

2.每接收到客户端的链接请求,即创建一个进程,在此进程中完成与客户端的通讯。新创建的进程能够获得用户的请求的文件,在磁盘的指定位置将此文件读取出来,并经过socket将文件信息返回到申请客户端(浏览器),然后此进程执行结束。

 

Webserver.cpp
//编写命令行参数
        wchar_t  pCmdLine[256];
        wsprintf(pCmdLine, L"D:\xukai\学习\操作系统实验\webServer1\Process\Debug\Process.exe %d", socketconn);
        //声明创建进程参数
        LPPROCESS_INFORMATION pi=NULL;
        STARTUPINFO si = { sizeof(si) };
        //创建进程并验证是否成功
        BOOL ret = CreateProcess(LPCTSTR("Process.exe"),pCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
        if (ret) {
            // 关闭子进程的主线程句柄
            CloseHandle(pi->hThread);

            // 关闭子进程句柄
            CloseHandle(pi->hProcess);
        }

Process.cpp
// Process.cpp : 定义控制台应用程序的入口点。
//
#pragma once

#include "stdafx.h"

#include <iostream>
#include <fstream>
#include <stdio.h> 
#include <Winsock2.h> 
#include <string>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
//文件路径
static string dir = "D:\xukai\学习\操作系统实验\webServer1\webServer\Debug";
void main(int argc, CHAR* argv[])
{
    cout << argc << endl;
    cout << argv[0] << endl;
    cout << argv[1] << endl;
    //连接成功后与客户端进行会话
    char recvBuff[1024];
    string sendBuff;
    string locDir;
    ifstream fp;
    SOCKET socketconn = atoi(argv[1]);

    //接收请求
    if (recv(socketconn, recvBuff, 1024, 0) == SOCKET_ERROR)
    {
        return;
    }

    //读取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;

    //    locDir.insert(0,1,'.');
    //打开http请求文件进行读取
    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);
            //将读取的内容追加入sendBuff中
            sendBuff.append(buffer);
            buffer[0] = '\0';
        }
    }
    fp.close();
    //响应请求,将页面信息发送到客户端

    if (send(socketconn, sendBuff.c_str(), sendBuff.length(), 0) == SOCKET_ERROR)
    {
        return;
    }

    shutdown(socketconn, 1);
    //}
    //关闭连接
    closesocket(socketconn);

    return;
}

 

三.思考题

3.思考一下,为什么有时在IE浏览器中,请求网页在服务器中会收到多个请求?我们该怎样利用这种情况,来优化服务器?

答:因为一个网页分为文本和图片等,是不同的文件,所以需要分别请求,如果多线程并行传输就会快点。

 

4.能否解决网页名称为中文的问题

答:如果中文不能被识别的话可以通过两次编译码实现,转成字符串传输。

 

 5.为什么在IE浏览器中显示的内容缺少了一些图片等信息?怎么来解决

答:个人认为是在客户发出申请,服务器返回socket包时有丢失,或者在阻塞的时候遗漏了信息包。

 

 

版权声明:本文由19463331韦德国际发布于19463331韦德国际,转载请注明出处:操作系统实验报告二