Socket编程日志 Week3
一、实验概要
第三周实验只需实现一个重要的功能:HTTP pipeline。
具体来说,服务器需要按照RFC2616规定的顺序处理HTTP的并发请求。同时,对于错误的请求,服务器响应错误后不会影响后续消息的响应。
二、协议设计
1. Pipeline模块
首先,根据RFC2616的规定,应先处理先到达的请求,后处理后达到的请求。而在实验的环境中,体现为先处理整体请求输入中最靠前的请求,再逐个向后进行处理。
下面对此模块进行设计。
数据结构设计
在第一周实验中,给出过HTTP请求的结构如下所示。
由于在本实验中所支持的请求均不包含请求数据的部分,因此在服务器处理至最后的回车符和换行符后即可认为一个请求已经结束。经过观察容易发现,在请求报文的最后会出现"\r\n\r\n"
这一特殊字符串,且在请求报文的其它地方均不会出现此字符串,因此可将其作为检测不同请求的分隔符,来对不同的请求报文进行区分。
协议规则设计
在清楚了如何识别不同请求报文的分隔符后,只需简单的根据分隔符将所有请求拆分开,再对每个请求进行响应即可。在对消息进行拆分时,应按如下步骤进行。
- 读取全部请求报文,从头开始进行拆分;
- 记录当前的处理位置,若超出报文长度则代表拆分完毕;
- 通过串匹配算法匹配未处理串中第一个分隔符的末尾位置,即为当前请求的结束位置;
- 计算匹配长度;
- 根据匹配长度提取当前请求,并传入服务器响应模型进行响应;
- 更新当前处理位置为请求结束位置
- 循环处理直至拆分完毕。
根据以上设计,可以绘制拆分流程图如下。
2. 客户端接收模块
需要注意,由于在先前框架代码的设计中,客户端每发送一次请求报文只会接受一个响应,而在本次实验中服务器会尝试发送多个响应。因此还需要对客户端程序进行一定修改,使其支持对多个响应的连续接收。
协议规则设计
这部分的设计比较简单,只需将框架代码中接收响应的模块放在一个循环结构中,每接收到一个合法响应便输出即可。
三、协议实现
1. Pipeline模块
在对Pipeline模块进行实现时,除去对前述流程的实现外,缓冲区的管理也是一个比较重要的问题。
本模块的处理过程中需要存储三部分内容:全部请求报文、单次请求报文和单次请求的响应。因此,可以设置3个不同的缓冲区:buf_all
、buf_recv
、buf_send
,分别存储上述三种数据。也正因此,本次实验中还需对原先的服务器响应模块进行部分修改,以匹配新的缓冲区设计。
根据前面的流程图和对缓冲区的新设计,可以得到Pipeline模块的伪代码如下:
1 | BUFFER buf_all, buf_recv, buf_send |
由此便可完成Pipeline模块的实现。
2. 客户端接收模块
此模块的实现只需在框架代码上进行少量更改即可。框架代码可以用如下伪代码表示。
1 | IF RECV FROM SERVER TO buf AND buf.length > 1 |
在此只需将if
判断语句更改为while
循环语句,并进行一些细节上的匹配即可。更改后可以用如下伪代码表示。
1 | WHILE RECV FROM SERVER TO buf AND buf.length > 1 |
至此,可以完成对客户端接收多个响应功能的实现。
结果分析
本地测试
框架代码中给出了一个可用于测试的request_pipeline
文件,本次实验实现的程序也可以对该测试文件得到正确的结果。但该文件内容较长,不易于展示,因此这里自行编写一个较为简单的测试文件sample_pipeline
,其中包含3个连续的HTTP请求,分别为未实现请求,格式错误的请求,以及HTTP GET
请求,以此验证服务器能否正确拆分并响应请求,且对错误请求的处理不会影响后续请求的处理。
测试结果如下。
可以看到,服务器对每个请求都进行了正确的响应,且响应顺序正确。
此外,根据日志记录也可以看出,服务器对每个拆分出的请求都生成并发送了正确的响应。
Autolab测试
实验总结
了解并成功实现了对连续HTTP请求的拆分和分别处理,对HTTP请求的结构有了更进一步的认识;加深了对缓冲区管理的意识和了解程度,明白了某些复杂功能需要基于良好的缓冲区设计;更深入的理解了客户端和服务器间的通信方式,并成功实现了客户端对多个连续响应的接收和打印。
- Title: Socket编程日志 Week3
- Author: 梦猫
- Created at : 2024-05-29 01:15:25
- Updated at : 2024-05-31 22:00:45
- Link: https://mengmaor.github.io/2024/05/29/Socket编程记录-Week3/
- License: All Rights Reserved © 梦猫