配置web服务器+编写简单页面+分析交互过程

目录

配置web服务器

IIS配置web服务器

C++搭建简单的web服务器

编写web页面

程序测试

IIS配置测试

C++程序测试

Wireshark捕获交互过程及分析

三次握手

请求报文

请求行

请求头

请求体

响应报文

响应行

响应头

响应体

四次挥手

实验中遇到的问题及分析

参考资料


配置web服务器

IIS配置web服务器

使用Windows自带的IIS配置web服务器,具体配置情况如下:

网站名称可以自己取,物理路径是我们编写的html文件所在的地方。

IP地址我设置成了本地,端口默认为80,也可以自由更改,注意不要和其他被使用的端口重复了!

我没有修改默认文档,因此我的html文件必须被命名为index.html,大家也可以自行修改。

C++搭建简单的web服务器

C++实现流式socket聊天程序的基础上,我们也可以采用流式socket的方式搭建一个简单的web服务器。主要的流程大体相同,但是发送和接收消息的部分改为接收客户端访问页面的请求头,并发送响应报文

由于本实验的重点并非编程,我编写的程序中没有对客户的请求头进行分析,从而作出相应的处理,只是简单地接收请求头,并发送响应报文,响应体为我编写的html文件。

C++程序的主要代码如下(其他部分代码与实验1大体相同):

// 接收客户端的连接请求
while (true) {
    sockaddr_in addrClient;
    int len = sizeof(sockaddr_in);
    // 接收客户端的连接请求并创建新的套接字
    SOCKET sockConn = accept(sockServer, (SOCKADDR*)&addrClient, &len);
    if (sockConn != INVALID_SOCKET) {
        cout << "[ACCEPT CONNECTION REQUEST!]" << endl;
        cout << "---------------------------------------------------" << endl;
        char recvBuf[2652];
        memset(recvBuf, 0, sizeof(recvBuf));
        // 获取客户端的请求头
        int recvLen = recv(sockConn, recvBuf, 2652, 0);
        if (recvLen == -1) {
            cout << "Request error!" << endl;
            break;
        }
        else {
            cout << sizeof(recvBuf) << " bits received." << endl;
            cout << recvBuf << endl;
            cout << "---------------------------------------------------" << endl;

            // 响应报文
            char response[2652];
            memset(response, 0, sizeof(response));
            // 计算时间
            char tmp[32] = { NULL };
            time_t t = time(0);
            strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", localtime(&t));
            string str = "HTTP/1.1 200 OK\r\n""Date: ";
            str.append(tmp);
            str.append(" GMT\r\n");
            // 响应头,随便写了一点,并不完整,详细的分析看下文介绍
            str.append("Server: Roslin's web server(Windows)\r\n"
                       "Content-length: 1583\r\n"
                       "Content-Type: text/html; charset=UTF-8\r\n"
                       "Keep-Alive: timeout=10, max=100\r\n"
                       "Connection: Keep-Alive\r\n\r\n");
            // Conten-length一定要和消息体(html文件)的长度一致!!!否则无法正确显示
            // 打开html文件,参数r表示仅供读取
            FILE* file = fopen("WebPage.txt", "r");
            if (file == NULL) {
                cout << "Can not open the file!" << endl;
                return 0;
            }
            char html[1024] = "";
            do {
                memset(html, 0, sizeof(html));
                fgets(html, 1024, file);
                str.append(html);
            } while (!feof(file));

            // 发送响应报文,发送的消息长度必须和实际的一致,太长了会读入乱码!!!
            strcpy_s(response, str.c_str());
            send(sockConn, response, str.length(), 0);
            cout << str.length() << " bits response sent." << endl;
            cout << str << endl;
            cout << "---------------------------------------------------" << endl;
        }
    }
    // 关闭监听套接字
    closesocket(sockConn);
}

虽然我的响应头发送的连接方式是Keep-Alive,但是大家可以看到我发送完响应报文之后就关闭监听了套接字,相当于关闭了TCP连接,这是因为之后我们需要捕获TCP四次挥手的过程(其实是因为我一开始没想清楚)

编写web页面

我编写了一个简单的html文件,用来显示我的个人主页。主要内容有姓名、学号、专业、学院、学校、个人logo(一只可爱的小考拉)。还加入了网易云音乐的外链接和背景图片,使界面更具有观赏性。具体的代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Roslin's Home Page</title>
    <style>
		body 
		{
			background-image: url(https://img.zmtc.com/2019/0815/20190815113422287.jpg);
			background-size: cover;
		}
	</style>
    <style>
    div.transbox
            {
              width: 1050px;
              height: 420px;
              margin: 90px 90px;
              background-color: #ffffff;
              border: 1px solid #FFFFFF;
              opacity:0.8;
            }
    </style>
    <style>
		h1 {text-align: center;}
		h2.ex1 {margin-left:5cm;}
		h3.ex1 {margin-left:5cm;}
		p{text-align: right;}
		p.ex1{margin-right: 2cm;}
	</style>
    <style>
   	img.ex1{margin-left:5cm;border-radius:100%;overflow:hidden;position: absolute;top: 50;left: 150;}
	</style>
</head>
<body>
	<div class="background">
		<div class="transbox">
            <h1>个人简介</h1>
            <h2 class="ex1">Roslin</h2>
            <h3 class="ex1">学号:xxx</h3>
            <h3 class="ex1">专业:xxx</h3>
            <h3 class="ex1">学院:xxx</h3>
            <h3 class="ex1">学校:xxx</h3>
            <p class="ex1">xxxxx</p>
            <img src="https://tupian.qqw21.com/article/UploadPic/2015-5/201552323315986462.jpg" height="150px" width="150px" class="ex1" title="logo"/>
		</div>
    </div>
    <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=298 height=52 src="http://music.163.com/outchain/player?type=2&id=456370728&auto=1&height=32"></iframe>
</body>
</html>

注意:

  • 插入的图片如果是本地的,必须放在html文件的根目录之下,否则要放完整的地址。但是插入本地图片用C++编程的方式无法正确显示,用IIS配置的方式可以。
  • 用电脑浏览器打开网易云音乐,选择想要的歌曲/歌单,点击生成外链接,复制html代码即可。但是有些歌曲因版权问题无法生成外链接! 

特别声明:本人没学过html,因此界面非常简单。

程序测试

IIS配置测试

直接打开127.0.0.1(80端口为默认的,不用加),即可看到我编写的web页面,测试成功。

C++程序测试

运行WebServer.cpp,打开浏览器,输入localhost:81(程序中指定的本地ip及端口号),可以看到我编写的web页面,测试成功。

懒得放图...

Wireshark捕获交互过程及分析

使用Wireshark捕获交互过程,可以看到TCP握手、浏览器的GET请求、我编写的响应报文和TCP挥手。

三次握手

  1. 第一次握手:客户端发送序列号Seq=0的SYN报文到服务器,表示请求建立连接。
  2. 第二次握手:服务器收到客户端的SYN报文,发送序列号Seq=0、确认号Ack=1的SYN, ACK报文到客户端,表示同意建立连接。
  3. 第三次握手:客户端收到服务器的SYN, ACK报文,发送序列号Seq=1、确认号Ack=1的ACK报文到服务器,表示确认建立连接。

请求报文

GET / HTTP/1.1
Host: localhost:81
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="106", "Microsoft Edge";v="106", "Not;A=Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.47
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6

请求行

  • 请求方法:GET, POST, HEAD, PUT, DELETE。
  • 请求url:在本实验中,由于是同一台主机,于是省略了。
  • http版本:在本实验中是HTTP/1.1。

请求头

  • Host:主机。
  • Connection:连接方式,keep-alive说明服务器在发送响应报文后不关闭TCP连接。
  • Cache-Control:缓存控制,max-age表示客户端希望接收资源的存在时间的最大值,在本实验中,意思是客户端希望接收一个新的资源。
  • sec-ch-ua:浏览器的版本。
  • sec-ch-ua-mobile:浏览器是否在移动设备上打开。
  • sec-ch-ua-platform:浏览器所在的操作系统。
  • Upgrade-Insecure-Requests:请求服务端支持以下升级机制。
  • User-Agent:客户端请求的相关信息,实验如浏览器、操作系统等。
  • Accept:客户端希望接收的响应体的数据类型。
  • Sec-Fetch-Site:表示一个请求发起者的来源与目标资源来源之间的关系。
    • cross-site:跨域请求;
    • same-origin:发起和目标站点源完全一致;
    • same-site:实验如一级请求二级域名;
    • none:如果用户直接触发页面导航,实验如在浏览器地址栏中输入地址,点击书签跳转等。
  • Sec-Fetch-Mode:请求的模式。
    • cors:跨域请求;
    • no-cors:限制请求,只能使用请求方法(get/post/put)和请求头(accept/accept-language/content-language/content-type);
    • same-origin:如果使用此模式向另外一个源发送请求,显而易见,结果会是一个错误。
    • navigate:表示这是一个浏览器的页面切换请求,仅在浏览器切换页面时创建,该请求应该返回html;
    • websocket:建立websocket连接。
  • Sec-Fetch-User:表示导航请求激发的原因。
    • true(?1):导航请求由用户激活触发(鼠标点击/键盘);
    • false(?0):导航请求由用户激活以外的原因触发;
  • Sec-Fetch-Dest:请求的目的,表示客户端希望获取什么样的资源。
  • Accept-Encoding:接受的编码方式。
  • Accept-Language:接受的语言。

请求体

POST和PUT方法包含请求体,本实验中是GET请求,不包含请求体。

响应报文

HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Last-Modified: Thu, 27 Oct 2022 02:34:23 GMT\r\n
Accept-Ranges: bytes\r\n
ETag: "b7e928a0ace9d81:0"\r\n
Server: Microsoft-IIS/10.0\r\n
Date: Thu, 27 Oct 2022 02:34:43 GMT\r\n
Content-Length: 1631\r\n
\r\n
[HTTP response 1/2]
[Time since request: 0.003017000 seconds]
[Request in frame: 5]
[Next request in frame: 29]
[Next response in frame: 31]
[Request URI: http://127.0.0.1/favicon.ico]
File Data: 1631 bytes

由于C++ socket编程的响应报文是我自己编写的,内容比较简单,不够完整,因此在这里分析使用IIS搭建的服务器发送的响应报文。

响应行

  • http版本:在本实验中,是HTTP/1.1,必须和请求报文的协议版本匹配。
  • 状态码和解释:表示请求的结果。
    • 200 OK:请求成功;
    • 301 Moved Permanently:请求的对象被移走,新的位置在响应中通过Location: 给出;
    • 400 Bad Request:服务器不能解释请求报文;
    • 404 Not Found:服务器中找不到请求的文档;
    • 505 HTTP Version Not Supported:服务器不支持相应的HTTP版本。

响应头

  • Date:发送响应报文的时间。
  • Server:服务器的版本和平台。
  • Last-Modified:最近一次修改的时间。
  • ETag:被请求变量的实体值,是一个可以与Web资源关联的记号。
  • Accept-Ranges:服务器支持的可用于定义范围的单位。
  • Content-Length:响应体的长度。
  • Keep-Alive:TCP通道可以保持的时间和最多接受的请求次数。
  • Connection:连接方式,同上。
  • Content-Type:响应体的内容类型和编码方式。

响应体

本实验中,响应体就是我编写的html文件,在次不再赘述。

四次挥手

IIS服务器捕获的四次挥手:

C++ socket编程捕获的四次挥手:

  1. A向B发送FIN, ACK报文,请求终止连接。
  2. B收到A发送的FIN, ACK报文后,回复ACK报文,表示确认收到了终止连接的请求。
  3. B向A发送FIN, ACK报文,请求终止连接。
  4. A收到B发送的FIN, ACK报文后,回复ACK报文,表示确认收到了终止连接的请求,双方正式终止连接。

客户端和服务器都可以主动发起挥手动作。在IIS服务器捕获时四次挥手非常标准,我关闭了浏览器,由客户端先向服务器发送终止连接的请求。

但在C++ socket编程捕获的文件中, 只能看到三次挥手,但是观察Seq和Ack的值和连接的过程,一切正常。查阅相关资料后分析,这是因为我的服务器是通过socket编程实现的,发送完响应报文之后,调用close函数时就会向客户端发送终止连接的请求,这一步并不会在捕获文件中体现。之后客户端(64400)回复ACK报文确认收到了终止连接的请求也印证了这一点。

实验中遇到的问题及分析

  1. 在使用C++搭建简单的web服务器时,由于对html的了解不够深刻,发送的响应报文不正确,一直无法正常打开网页。经过分析发现两个问题:第一,发现Content-length一定要和消息体(html文件)的长度一致,否则无法正确显示;第二,发送响应报文,发送的消息长度必须和实际的一致,太长了会读入乱码。虽然能够顺利完成实验,但是这个程序只是一个很简单的web服务器,没有对请求报文进行解析,响应报文也只有一种情况。希望后续能够在对http协议学习更深入的基础上编写一个完整的web服务器。
  2. 在编写web界面时,由于对于html语言了解不够深刻,出现了很多语法错误,也难以实现想要的效果。经过对html语言的初步学习后,能够实现预期的界面。但是这只是一个很简单的个人主页,希望以后能够改进。
  3. 在使用Wireshark捕获交互过程时,一开始对于软件不够熟悉,不清楚如何使用。后来可以正常捕获,但是捕获的内容很多,经过学习我发现可以使用过滤条件,就能快速定位到我们需要的交互过程。
  4. 在IIS服务器捕获的文件中,一开始我看到的响应报文总是304 Not Modified,但是依然能正常打开网页。后来发现是因为网页有缓存机制,如果第一次连接之后,html文件没有改变,就不会重新返回200 OK的响应报文。因此,我稍微修改了一下html文件,就成功捕获到了200 OK的响应报文。
  5. 在C++ socket编程捕获的文件中,我只观察到三次挥手,但是观察Seq和Ack的值和连接的过程,一切正常。查阅相关资料后分析,这是因为我的服务器是通过socket编程实现的,发送完响应报文之后,调用close函数时就会向客户端发送终止连接的请求,这一步并不会在捕获文件中体现。

参考资料

Sec-Fetch-*请求头,了解下? - 福禄网络研发团队 - 博客园

使用 WireShark 分析 TCP/IP 三次握手 和 四次挥手 - bylijian - 博客园

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
浏览器通过 Web 服务器与数据库交互过程通常包含以下几个步骤: 1. 用户在浏览器上输入 URL,浏览器向 Web 服务器发送 HTTP 请求。 2. Web 服务器接收到请求后,会根据请求的内容进行处理,并将处理结果返回给浏览器。如果请求的内容需要从数据库中获取数据,Web 服务器会通过编写数据库查询语句来查询数据库。 3. 数据库接收到查询请求后,会根据查询语句查询数据库中的数据,并将查询结果返回给 Web 服务器。 4. Web 服务器将查询结果组织成 HTML 页面并将其返回给浏览器。 5. 浏览器接收到 Web 服务器返回的 HTML 页面后,会解析页面内容,并根据页面中包含的 JavaScript 代码与 Web 服务器进行交互,例如使用 AJAX 技术向 Web 服务器请求数据。 6. Web 服务器接收到 AJAX 请求后,会根据请求的内容进行处理,并将处理结果返回给浏览器。如果请求的内容需要从数据库中获取数据,Web 服务器同样会通过编写数据库查询语句来查询数据库,查询结果同样会返回给浏览器。 7. 浏览器接收到 Web 服务器返回的数据后,会根据数据内容更新页面内容,从而实现与数据库的交互。 需要注意的是,Web 服务器一般会充当中间层的角色,将浏览器发送的请求转发给数据库,并将数据库返回的数据包装成 HTML 页面返回给浏览器,起到了连接浏览器和数据库的桥梁作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值