forked from happysnaker/CSAPPLabsAndNotes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
proxy.c Writeup.txt
150 lines (113 loc) · 13.9 KB
/
proxy.c Writeup.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
代理实验室:编写缓存Web代理
0引言
Web代理是充当Web浏览器和终端服务器之间的中间人的程序。代替直接与最终服务器联系以获取网页,浏览器联系代理,该代理转发请求到最终服务器上。当最终服务器回复代理时,代理会将回复发送到浏览器。代理可用于许多目的。有时,防火墙中会使用代理,因此,防火墙只能通过代理与防火墙以外的服务器联系。代理也可以充当匿名者:通过剥离所有标识信息的请求,代理可以使浏览器对Web匿名服务器。通过存储来自服务器的对象的本地副本,甚至可以使用代理来缓存Web对象通过从缓存中读取请求而不是通过再次与之通信来响应将来的请求远程服务器。
在本实验中,您将编写一个简单的HTTP代理来缓存Web对象。在实验的第一部分中,您将设置代理以接受传入的连接,读取和解析请求,将请求转发到Web服务器,阅读服务器的响应,并将这些响应转发给相应的客户端。第一部分将涉及学习基本的HTTP操作以及如何使用套接字编写可通信的程序通过网络连接。在第二部分中,您将升级代理以处理多个并发连接。这将为您介绍处理并发这一关键的系统概念。在第三最后一部分,您将使用最近访问的简单主内存缓存将缓存添加到代理中网页内容。
将讲义文件复制到计划进行工作的Linux机器上的受保护目录中,然后然后发出以下命令:
linux> tar xvf proxylab-handout.tar
这将生成一个名为proxylab-handout的讲义目录。 README文件描述了各种文件的信息。
第一部分:实现Web代理转发功能
第一步是实现处理HTTP / 1.0 GET请求的基本顺序代理。其他要求类型(例如POST)是可选的。启动后,代理应侦听将指定其端口号的端口上的传入命令。建立连接后,您的代理应阅读整个请求并从客户端解析请求。它应该确定客户端是否发送了有效的HTTP请求。如果是这样,则它可以随后建立其自己与适当的Web服务器的连接,然后向客户端请求该对象指定的信息。最后,您的代理应阅读服务器的响应并将其转发给客户端。
1 HTTP / 1.0 GET请求
最终用户在地址中输入诸如http://www.cmu.edu/hub/index.html之类的URL时Web浏览器的浏览器栏,浏览器将向代理发送HTTP请求,该请求以以下行开头类似于以下内容:
GET http://www.cmu.edu/hub/index.html HTTP / 1.1
在这种情况下,代理应至少将请求解析为以下字段:主机名www.cmu.edu;以及路径或查询及其后的所有内容:/ hub / index.html。
这样,代理就可以确定应该打开与www.cmu.edu的连接,并以其开头发送自己的HTTP请求。
请求行格式如下:
GET /hub/index.html HTTP / 1.0
请注意,HTTP请求中的所有行都以回车符“ \ r”结尾,后跟换行符“ \ n”。还重要的是,每个HTTP请求都以空行终止:“ \ r \ n”。
您应该在上面的示例中注意到,网络浏览器的请求行以HTTP / 1.1结尾,而代理的请求行以HTTP / 1.0结尾。现代网络浏览器将生成HTTP / 1.1请求,但是您的代理应该处理它们,并将其作为HTTP / 1.0请求转发。重要的是要考虑到HTTP请求,甚至只是HTTP / 1.0 GET请求的子集,都可以令人难以置信的复杂。该教科书描述了HTTP事务的某些细节,但是您应该参考RFC 1945的完整HTTP / 1.0规范。理想情况下,您的HTTP请求解析器将完全除了一个细节外,根据RFC 1945的相关部分具有很强的鲁棒性:尽管该规范允许
对于多行请求字段,不需要您的代理正确处理它们。当然,您的代理人切勿因格式错误的请求而提前中止。
2 请求头
该实验的重要请求标头是:主机,用户代理,连接和代理连接
标头:
•始终发送主机。主机标头描述了最终服务器的主机名。例如,访问http:// www。cmu.edu/hub/index.html,您的代理将发送以下标头:
Host:www.cmu.edu
Web浏览器可能会将自己的Host标头附加到其HTTP请求。如果是在这种情况下,您的代理服务器应使用与浏览器相同的Host标头。
•您可以选择始终发送以下User-Agent标头:
用户代理:Mozilla / 5.0(X11; Linux x86_64; rv:10.0.3)Gecko / 20120305 Firefox / 10.0.3
标头在两行中提供,因为它不适合写在一行中,但是您的代理服务器应将标头发送为一行。
User-Agent标头标识客户端(根据操作系统等参数和浏览器),并且网络服务器通常使用标识信息来操纵其内容服务。发送此特定的User-Agent:字符串可能会改善内容和多样性在简单的telnet风格的测试中得到的回报。
•始终发送以下连接头:
Connection:close
•始终发送以下代理连接头:
Proxy-Connection:close
Connection和Proxy-Connection标头用于指定是否连接在第一次请求/响应交换完成后,它将保持活动状态。这是完全可以接受的(并建议)让您的代理为每个请求打开一个新的连接。指定close为这些标头的值会警告Web服务器,您的代理打算在首次请求/响应交换。为了您的方便,所描述的User-Agent标头的值以字符串形式提供给proxy.c中的常量。最后,如果浏览器将任何其他请求标头作为HTTP请求的一部分发送,则您的代理应转发他们不变。
3 端口号
本实验有两种重要的端口号:HTTP请求端口和代理的监听口。
HTTP请求端口是HTTP请求的URL中的可选字段。也就是说,URL可能是: http://www.cmu.edu:8080 / hub / index.html,在这种情况下,您的代理应该连接到端口8080上的主机www.cmu.edu,而不是默认的HTTP端口80。侦听端口是代理应在其上侦听传入连接的端口。您的代理应该接受一个命令行参数,该参数指定代理的侦听端口号。例如,
使用以下命令,您的代理应侦听端口15213上的连接:
linux> ./proxy 15213
您可以选择任何非特权侦听端口(大于1,024并且小于65,536),只要它不被其他进程使用。由于每个代理必须使用唯一的侦听端口,因此许多人会同时在每台计算机上工作时,提供了脚本port-for-user.pl可帮助您选择您自己的个人端口号。使用它根据您的用户ID生成端口号:
linux> ./port-for-user.pl droh
Droh:45806
port-for-user.pl返回的端口p始终是偶数。因此,如果您需要额外的端口号,例如对于Tiny服务器,您可以安全地使用端口p和p + 1。请不要选择您自己的随机端口。如果这样做,则存在干扰另一个用户的风险。
第II部分:处理多个并发请求
拥有顺序工作的代理后,应对其进行更改以同时处理多个请求。实现并发服务器的最简单方法是产生一个新线程来处理每个新连接要求。其他设计也是可能的,例如您的第12.5.5节中描述的预线程服务器教科书。
•请注意,线程应以分离模式运行,以避免内存泄漏。
•CS:APP3e教科书中介绍的open clientfd和open listenfd函数是
基于现代且独立于协议的getaddrinfo函数,因此是线程安全的。
第III部分:缓存Web对象
在实验的最后部分,您将向代理添加缓存,该缓存将最近使用的Web对象存储在记忆。 HTTP实际上定义了一个相当复杂的模型,Web服务器可以通过该模型给出有关以下方面的指令:他们服务的对象应该如何缓存,客户端可以指定如何在他们的对象上使用缓存代表。但是,您的代理将采用简化的方法。当您的代理从服务器接收到Web对象时,它应该在传输对象时将其缓存在内存中给客户。如果另一个客户端从同一服务器请求相同的对象,则您的代理无需重新连接到服务器;它可以简单地重新发送缓存的对象。显然,如果您的代理服务器要缓存所请求的每个对象,则将需要无限制的内存量。而且,由于某些Web对象大于其他Web对象,因此可能一个巨型对象将占用整个缓存,从而阻止其他对象根本不会被缓存。避免这些问题,您的代理服务器应同时具有最大缓存大小和最大缓存对象大小。
最大缓存大小
整个代理的缓存应具有以下最大大小:MAX_CACHE_SIZE = 1 MiB
在计算其缓存大小时,代理必须仅计算用于存储实际Web对象的字节;
任何多余的字节(包括元数据)都应忽略。
最大对象尺寸
您的代理应仅缓存不超过以下最大大小的Web对象:
MAX_OBJECT_SIZE = 100 KiB;
为方便起见,两个大小限制都作为宏提供在proxy.c中。实现正确缓存的最简单方法是为每个活动连接分配一个缓冲区,并在从服务器接收数据时累积最新数据。如果缓冲区的大小超过最大对象大小,则缓冲区可以被丢弃。如果在最大对象大小之前读取了整个网络服务器的响应,超过,则可以缓存该对象。使用此方案,您的代理可以获取的最大数据量,以下将用于Web对象的内容如下,其中T是活动连接的最大数量:
MAX_CACHE_SIZE + T * MAX_OBJECT_SIZE
LRU策略
您代理的缓存应采用近似于最近最少使用(LRU)驱逐的驱逐策略政策。它不一定严格是LRU,但应该相当接近。请注意,读取并写入对象算作使用该对象。
同步
对缓存的访问必须是线程安全的,并且确保对缓存的访问不受竞争条件的影响。可能是该部分实验中更有趣的方面。实际上,有一个特殊的要求多个线程必须能够同时从缓存中读取。当然,只有一个线程应该允许一次写入高速缓存,但是对于读取器而言,该限制一定不存在。因此,使用一个大的互斥锁来保护对缓存的访问不是可接受的解决方案。你可能想探索选项,例如对缓存进行分区,使用Pthreads读写器锁或使用信号以实现您自己的读者-作家解决方案。无论哪种情况,您都不必实施严格的LRU驱逐策略将为您提供一些灵活性,以支持多个读者。
评测
这项作业的总分为70分:
•BasicCorrectness:基本代理操作需要40分(自动评分)
•并发:处理并发请求需要15分(自动评分)
•缓存:工作缓存的15点(自动分级)
自动分级
您的讲义材料包括一个名为driver.sh的自动分级机,您的讲师将使用该自动分级机来分配在BasicCorrectness,并发性和缓存方面得分较高。从proxylab-handout目录中:
linux> ./driver.sh
您必须在Linux机器上运行驱动程序。
稳健性
与往常一样,您必须提供对错误,甚至畸形或恶意输入具有鲁棒性的程序。服务器通常是长时间运行的进程,并且Web代理也不例外。仔细考虑长时间运行的流程应应对不同类型的错误。对于许多错误,这肯定是不适合您的代理立即退出。健壮性还意味着其他要求,包括对错误情况(如分段)的无敌性错误以及缺少内存泄漏和文件描述符泄漏。
测试与调试
除了简单的自动分级机之外,您将没有任何示例输入或测试程序来测试您的实现。您将必须提出自己的测试,甚至可能需要自己的测试工具才能提供帮助您调试代码并确定何时具有正确的实现。这是真正的宝贵技能在世界范围内,确切的操作条件鲜为人知,而参考解决方案通常不可用。幸运的是,您可以使用许多工具来调试和测试代理。确保使用所有代码路径并测试一组具有代表性的输入,包括基本案例,典型案例和边缘案例。
小型Web服务器
您的讲义目录包含CS:APP Tiny Web服务器的源代码。虽然不如thttpd强大,CS:APP Tiny Web服务器将很容易修改,您可以根据需要进行修改。这也是一个合理的开始
指向您的代理代码。它是驱动程序代码用来获取页面的服务器。
telnet
如教科书(11.5.3)中所述,您可以使用telnet打开与代理的连接并发送 HTTP请求。
curl
您可以使用curl生成对任何服务器(包括您自己的代理)的HTTP请求。这是一个极端
有用的调试工具。例如,如果您的代理服务器和Tiny都在本地计算机上运行,则Tiny是
侦听端口15213,代理正在侦听端口15214,那么您可以通过
您的代理使用以下curl命令:
linux> curl -v --proxy http//localhost15214 http//localhost15213/home.html
*关于connect()到代理本地主机端口15214(#0)
*正在尝试127.0.0.1 ...已连接
7 *已连接到localhost(127.0.0.1)端口15214(#0)
> GET http:// localhost:15213 / home.html HTTP / 1.1
>用户代理:curl / 7.19.7(x86_64-redhat-linux-gnu)...
>主机:localhost:15213
>接受:* / *
>代理连接:保持活动
>
* HTTP 1.0,假设在正文之后关闭
<HTTP / 1.0 200确定
<服务器:Tiny Web服务器
<内容长度:120
<内容类型:text / html
<
<html>
<head> <title>测试</ title> </ head>
<身体>
<img align =“ middle” src =“ godzilla.gif”>
戴夫·奥哈拉龙
</ body>
</ html>
*关闭连接#0
网络浏览器
最终,您应该使用最新版本的Mozilla Firefox测试代理。关于Firefox的访问会自动将您的浏览器更新到最新版本。
要配置Firefox以使用代理,请访问首选项>高级>网络>设置看到您的代理通过真实的Web浏览器工作将非常令人兴奋。虽然功能您的代理将受到限制,您会注意到您能够通过以下方式浏览绝大多数网站您的代理。一个重要的警告是,在使用Web浏览器测试缓存时必须非常小心。所有现代网络浏览器拥有自己的缓存,您应在尝试测试代理服务器的缓存之前将其禁用缓存。