操作系统实验报告一

 

 

 

 

 

操作系统实验报告一

 

 

 

                       姓名:许恺

                       学号:2014011329

                       日期:929

 

 

 

 

 

 

 

 

 

 

一.相关技术资料——》

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上的WindowsWOW 为进程的方式运行。

lpCommandLine

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

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

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

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

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

传参

 

接收

 

二.报告内容

 

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

 

 

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包时有丢失,或者在阻塞的时候遗漏了信息包。

 

 

三、实验内容与要求 1、熟悉windows的编程接口,使用系统调用编程实现将参数1对应文件1.txt和参数2对应文件2.txt的内容合并到参数3对应文件zong.txt中(上传文件名为学号后5位ex0701.c)。 2、使用windows提供的命令将文件1.txt和文件2.txt的内容合并到文件total.txt中 (请将实现的操作命令写入下题批处理文件的第一行)。 3、主管助理小张经常接收公司员工发来的文件,开始为了节省时间,小张将下载的文件都保存在文件夹xiazai中(文件名如图1所示,下载后直接解压即可),这样不便于后期的统计和分类管理,现在领导要求必须为所有员工(90人)每人单独建立一个文件夹(以员工工号命名10201、10202......10290),然后将他们提交的文件分别剪切到各自对应的文件夹中(如图2所示)。于是小张开始为7名员工建立文件夹,再一个一个的去做……同学们想想有没有一种方法能快速完成所要求的操作呢? 请熟悉windows的命令接口,使用windows提供的常用命令copy、md、del等编写一个批处理文件(上传文件名为学号后5位ex0703.bat),实现所要求的功能: 1、启动linux系统或通过windows telnet到linux。 2、用huas用户名和密码123456登入系统中。 3、打开一终端窗口(在linux桌面上单击右键,选择从终端打开)。然后在其中输入以下命令实验。 4、熟悉常用操作命令. 5、编辑如下源代码(实验教材P86 1.进程创建)并保存 二、实验目的 (1)加深对进程概念的理解,明确进程和程序的区别。 (2)分析进程竞争资源现象,学习解决进程互斥的方法。 (3了解Linux系统中进程通信的基本原理。 三、实验内容与要求 (1)任务一:编写一段程序,使其实现进程的软中断通信。 要求:使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按DEL键);当捕捉到中断信号后,父进程用系统调用Kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止: Child Processll is Killed by Parent! Child Processl2 is Killed by Parent! 父进程等待两个子进程终止后,输出如下的信息后终止 Parent Process is Killed! (2)任务二:在上面的程序中增加语句signal (SIGNAL, SIG-IGN)和signal (SIGQUIT, SIG-IGN),观察执行结果,并分析原因。 (3)任务三:进程的管道通信 编制一段程序,实现进程的管道通信。 使用系统调用pipe()建立一条管道线;两个子进程P1和P2分别向管道中写一句话: Child 1 is sending a message! Child 2 is sending a message! 而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。 要求父进程先接收子进程P1发来的消息,然后再接收子进程P2发来的消息。 二、实验目的 自行编制模拟程序,通过形象化的状态显示,加深理解进程的概念、进程之间的状态转换及其所带来的PCB内容 、组织的变化,理解进程与其PCB间的一一对应关系。 三、实验内容与要求 1)设计并实现一个模拟进程状态转换及其相应PCB内容、组织结构变化的程序。 2)独立编写、调试程序。进程的数目、进程的状态模型(三状态、五状态、七状态或其它)以及PCB的组织形式可自行选择。 3)合理设计与进程PCB相对应的数据结构。PCB的内容要涵盖进程的基本信息、控制信息、资源需求及现场信息。 4)设计出可视性较好的界面,应能反映出进程状态的变化引起的对应PCB内容、组织结构的变化。 二、实验目的 存储管理的主要功能之一是合理地分配空间。请求页式管理是一种常用的虚拟存储管理技术。本实验的目的是通过请求页式管理中页面置换算法模拟设计,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。 三、实验内容与要求 通过计算不同算法的命中率比较算法的优劣。同时也考虑了用户内存容量对命中率的影响。页面失效次数为每次访问相应指令时,该指令所对应的页不在内存中的次数。 计算并输出下属算法在不同内存容量下的命中率。  先进先出的算法(FIFO); 最近最少使用算法(LRU) 二、实验目的 死锁会引起计算机工作僵死,因此操作系统中必须防止。本实验的目的在于使用高级语言编写和调试一个系统动态分配资源的简单模拟程序,了解死锁产生的条件和原因,并采用银行家算法有效地防止死锁的发生,以加深对课堂上所讲授的知识的理解。 三、实验内容与要求 设计有n个进程共享m个系统资源的系统,进程可动态的申请和释放资源,系统按各进程的申请动态的分配资源。 系统能显示各个进程申请和释放资源,以及系统动态分配资源的过程,便于用户观察和分析。 四、算法描述(含数据结构定义)或流程图 (一) 数据结构 1. 可利用资源向量Available ,它是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源的数目,其初始值是系统中所配置的该类全部可用资源数目。其数值随该类资源的分配和回收而动态地改变。如果Available(j)=k,标是系统中现有Rj类资源k个。 2. 最大需求矩阵Max,这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max(i,j)=k,表示进程i需要Rj类资源的最大数目为k。 3. 分配矩阵Allocation,这是一个n×m的矩阵,它定义了系统中的每类资源当前一分配到每一个进程的资源数。如果Allocation(i,j)=k,表示进程i当前已经分到Rj类资源的数目为k。Allocation i表示进程i的分配向量,有矩阵Allocation的第i行构成。 4. 需求矩阵Need,这是一个n×m的矩阵,用以表示每个进程还需要的各类资源的数目。如果Need(i,j)=k,表示进程i还需要Rj类资源k个,才能完成其任务。Need i表示进程i的需求向量,由矩阵Need的第i行构成。 上述三个矩阵间存在关系:Need(i,j)=Max(i,j)-Allocation(i,j)。 (二) 银行家算法 Request i 是进程Pi 的请求向量。Request i (j)=k表示进程Pi请求分配Rj类资源k个。当Pi发出资源请求后,系统按下述步骤进行检查: 1. 如果Request i ≤Need,则转向步骤2;否则,认为出错,因为它所请求的资源数已超过它当前的最大需求量。 2. 如果Request i ≤Available,则转向步骤3;否则,表示系统中尚无足够的资源满足Pi的申请,Pi必须等待。 3. 系统试探性地把资源分配给进程Pi,并修改下面数据结构中的数值: 二、实验目的 磁盘是高速、大容量、旋转型、可直接存取的存储设备。它作为计算机系统的辅助存储器,担负着繁重的输入输出工作,在现代计算机系统中往往同时会有若干个要求访问磁盘的输入输出要求。系统可采用一种策略,尽可能按最佳次序执行访问磁盘的请求。由于磁盘访问时间主要受寻道时间T的影响,为此需要采用合适的寻道算法,以降低寻道时间。本实验要求模拟设计一个磁盘调度程序,观察调度程序的动态运行过程。通过实验来理解和掌握磁盘调度的职能。 三、实验内容与要求 分别模拟如下磁盘调度算法,对磁盘进行移臂操作:  先来先服务算法  最短寻道优先算法 1. 假设磁盘只有一个盘面,并且磁盘是可移动头磁盘。 2. 磁盘是可供多个进程共享的存储设备,但一个磁盘每个时刻只能为一个进程服务。当有进程在访问某个磁盘时,其它想访问该磁盘的进程必须等待,直到磁盘一次工作结束。当有多个进程提出输入输出请求而处于等待状态时,可用磁盘调度算法从若干个等待访问者中选择一个进程,让它访问磁盘。为此设置“驱动调度”进程。 3. 由于磁盘与处理器是并行工作的,所以当磁盘在为一个进程服务时,占有处理器的其它进程可以提出使用磁盘(这里我们只要求访问磁道),即动态申请访问磁道,为此设置“接受请求”进程。 4. 为了模拟以上两个进程的执行,可以考虑使用随机数来确定二者的允许顺序,参考程序流程图。 5. “接受请求”进程建立一张“进程请求I/O”表,指出等待访问磁盘的进程要求访问的磁道,表的格式如下: 进程名 要求访问的磁道号 6. 磁盘调度的功能是查“请求I/O”表,当有等待访问的进程时,按磁盘调度算法从中选择一个等待访问的进程,按其指定的要求访问磁道。流程图中的“初始化”工作包括:初始化“请求I/O”表,设置当前移臂方向;当前磁道号。并且假设程序运行前“请求I/O”表中已有若干进程(4~8个)申请访问相应磁道。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值