zoukankan      html  css  js  c++  java
  • 操作系统实验报告一

     

     

     

    操作系统实验报告一

                           姓名:许恺

                           学号: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("监听失败!
    ");
        }
        while (true)
        {
            SOCKET socketconn;
            socketconn = accept(socketSrv, (SOCKADDR*)&addrCli, &len);
            //接受连接
    客户端反应,服务端接收
            if (socketconn == SOCKET_ERROR)
            {
                printf("接受连接失败!
    ");
                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] = '';
                }
    读文件,将文件写到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] = '';
            }
        }
        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包时有丢失,或者在阻塞的时候遗漏了信息包。

     

  • 相关阅读:
    HTML
    python io
    python 线程进程
    python socket
    python 面向对象2
    python 面向对象
    python hashlib模块
    python configparser模块
    python logging模块
    数组去重方法汇总
  • 原文地址:https://www.cnblogs.com/xukaiae86/p/6444902.html
Copyright © 2011-2022 走看看