《计算机网络—自顶向下方法》 第二章套接字编程:4.多线程Web代理服务器

实验描述

本编程作业的题目描述:

在本实验中,您将了解Web代理服务器的工作原理及其基本功能之一 —— 缓存
您的任务是开发一个能够缓存网页的小型Web代理服务器。这是一个很简单的代理服务器,它只能理解简单的GET请求,但能够处理各种对象 —— 不仅仅是HTML页面,还包括图片。
通常,当客户端发出一个请求时,请求将被直接发送到Web服务器。然后Web服务器处理该请求并将响应消息发送客户端。为了提高性能,我们在客户端和Web服务器之间建立一个代理服务器。现在,客户端发送的请求消息和Web服务器返回的响应消息都要经过代理服务器。换句话说,客户端通过代理服务器请求对象。代理服务器将客户端的请求转发到Web服务器。然后,Web服务器将生成响应消息并将其传递给代理服务器,代理服务器又将其发送给客户端。
在这里插入图片描述
代码
您将在下面找到客户端的代码框架。 您需要完成代码框架。需要您填写代码的地方标有#Fill in start和#Fill in end。 每个地方都需要填写至少一行代码。


代理服务器的Python代码框架:

from socket import *
import sys

if len(sys.argv) <= 1:
    print 'Usage : "python ProxyServer.py server_ip"\n[server_ip : It is the IP Address Of Proxy Server'
	sys.exit(2)
# Create a server socket, bind it to a port and start listening
tcpSerSock = socket(AF_INET, SOCK_STREAM)
# Fill in start.
# Fill in end.
while 1:
	# Strat receiving data from the client
	print 'Ready to serve...'
	tcpCliSock, addr = tcpSerSock.accept()
	print 'Received a connection from:', addr
	message = # Fill in start. # Fill in end.
	print message
	# Extract the filename from the given message
	print message.split()[1]
	filename = message.split()[1].partition("/")[2]
	print filename
	fileExist = "false"
	filetouse = "/" + filename
	print filetouse
	try:
		# Check wether the file exist in the cache
		f = open(filetouse[1:], "r")
		outputdata = f.readlines()
		fileExist = "true"
		# ProxyServer finds a cache hit and generates a response message
		tcpCliSock.send("HTTP/1.0 200 OK\r\n")
		tcpCliSock.send("Content-Type:text/html\r\n")
		# Fill in start.
		# Fill in end.
			print 'Read from cache'
	# Error handling for file not found in cache
	except IOError:
		if fileExist == "false":
			# Create a socket on the proxyserver
			c = # Fill in start. # Fill in end.
			hostn = filename.replace("www.","",1) 
			print hostn
			try:
				# Connect to the socket to port 80
				# Fill in start.
				# Fill in end.
				# Create a temporary file on this socket and ask port 80
				for the file requested by the client
				fileobj = c.makefile('r', 0)
				fileobj.write("GET "+"http://" + filename + " HTTP/1.0\n\n")
				# Read the response into buffer
				# Fill in start.
				# Fill in end.
				# Create a new file in the cache for the requested file.
				# Also send the response in the buffer to client socket and the corresponding file in the cache
				tmpFile = open("./" + filename,"wb")
				# Fill in start.
				# Fill in end.
			except:
				print "Illegal request"
		else:
			# HTTP response message for file not found
			# Fill in start.
			# Fill in end.
	# Close the client and the server sockets
	tcpCliSock.close()
# Fill in start.
# Fill in end.

我的python实现代码(参考一位github博主的):

from socket import *
import sys
import os

#if len(sys.argv) <= 1:
#    print ('Usage : "python ProxyServer.py server_ip"\n[server_ip : It is the IP Address Of Proxy Server')
#	sys.exit(2)

# 为代理服务器 创建一个TCP套接字、绑定端口号、设置服务器最大连接客户机数量为3(因为是多线程Web服务器)
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(('',1234))
tcpSerSock.listen(3)

while 1:
	# 准备从客户机接收响应消息
	print ('准备从客户机接收响应消息...')
	tcpCliSock, addr = tcpSerSock.accept()
	print ('接收到一个连接,来自:', addr)
	
	# 获取客户机发送过来的消息
	message = tcpCliSock.recv(4096).decode()
	print ('客户机发送过来的消息:',message)
	
	# 从消息从提取出文件名
	filename = message.split()[1].partition("//")[2].replace('/','_')
	print ('文件名:',filename)
	fileExist = "false"
	
	try:
		# 检查要访问的文件是否在此Web代理服务器中
		print ('开始检查代理服务器中是否存在文件:',filename)
		f = open(filename, "r")
		outputdata = f.readlines()
		fileExist = "true"
		print ('文件存在在代理服务器中')
		# 文件存在在代理服务器中,返回响应消息(请求的web网页)给客户机
		#tcpCliSock.send("HTTP/1.0 200 OK\r\n")
		#tcpCliSock.send("Content-Type:text/html\r\n")
		for i in range(0,len(outputdata)):
				tcpCliSock.send(outputdata[i].encode())	
		print ('Read from cache')
			
	# 文件不在代理服务器当中,代理服务器就会向远端服务器请求消息,保存好了再返回给客户机
	except IOError:
		if fileExist == "false":
			print ('文件不在代理服务器当中,开始向远端服务器请求网页')
			# 在代理服务器中创建一个TCP套接字
			c = socket(AF_INET,SOCK_STREAM)
			
			hostn = message.split()[1].partition("//")[2].partition("/")[0]
			print ('Host Name: ',hostn)
			try:
				# TCP套接字c 连接到远端服务器80端口
				c.connect((hostn,80))
				print ('套接字连接到主机的80号端口')
				
				# 在套接字上创建一个临时的文件,而且要向80端口(远端服务器)请求信息
				#for the file requested by the client
				#fileobj = c.makefile('r', 0)
				#fileobj.write("GET "+"http://" + filename + " HTTP/1.0\n\n")
				
				# 代理服务器 读取 从远端服务器从响应的消息
				c.sendall(message.encode())
				buff = c.recv(4096)
				tcpCliSock.sendall(buff)
				
				# 在代理服务器中 创建一个新的文件 用于存放请求过来的消息
				# 将代理服务器中的响应 发送到客户端套接字,并将相应的文件发送到缓存中
				tmpFile = open("./" + filename,"w")
				tmpFile.writelines(buff.decode().replace('\r\n','\n'))
				tmpFile.close();
				
			except:
				print ("代理服务器向远端服务器请求网页失败")
		else:
			# 如果客户机请求的消息在远端服务器也找不到,就说明请求不到了
			print ('文件存在,但是还是出现了 IOError异常')

	# 关闭客户机 和 代理服务器的TCP套接字
	print ('关闭套接字:tcpCliSock')
	tcpCliSock.close();
# 关闭代理服务器 和 服务器的TCP套接字
print ('关闭套接字:tcpSerSock')
tcpSerSock.close();

运行结果:

  1. 直接向远端服务器请求web网页:http://gaia.cs.umass.edu/wireshark-labs/INTRO-wireshark-file1.html
    在这里插入图片描述
  2. 修改浏览器设置(让网页直接请求本地的代理服务器)
    在这里插入图片描述
  3. 重新打开网页,发现打不开,因为此时还未启动代理服务器(自己写的ProxyServer.py)
    在这里插入图片描述
    4.启动代理服务器(直接运行py代码)
    在这里插入图片描述
  4. 重新打开web网页,开始第一次请求代理服务器(代理服务器中找不到所需的web网页,然后会转向请求远端服务器)
    在这里插入图片描述
  5. 从远端服务器会响应代理服务器的请求,从而会生成一个缓存文件(位于代理服务器同一目录)。
    在这里插入图片描述
  6. 重新打开web网页,发现可以直接从代理服务器中请求到网页了。
    在这里插入图片描述

可选练习【待完成】

  1. 目前代理服务器不能处理错误。这可能会导致一些问题,当客户端请求一个不可用的对象时,由于“404 Not Found”响应通常没有响应正文,而代理服务器会假设有正文并尝试读取它。
  1. 当前代理服务器只支持HTTP GET方法。通过添加请求体来增加对POST的支持。
  1. 缓存:每当客户端发出特定请求时,典型的代理服务器会缓存网页。缓存的基本功能如下:当代理获得一个请求时,它将检查请求的对象是否已经在缓存中,如果是,则从缓存返回对象,从而不用联系服务器。如果对象未被缓存,则代理从服务器获取该对象,向客户端返回该对象,并缓存一个拷贝以备将来的请求。在实际环境下,代理服务器必须验证被缓存的响应是否仍然有效,并且它们能对客户端正确响应。您可以在RFC 2068中阅读有关缓存及其在HTTP中实现方式的更多细节。添加上述简单的缓存功能。您不需要实现任何替换或验证策略。然而您需要实现的是,将请求和响应写入磁盘(即缓存)并能从磁盘中获取它们,用于缓存被请求命中时。为此,您需要在代理中实现一些内部数据结构,以便跟踪哪些请求处于缓存中时,以及它们在磁盘上的位置。您也可以将此数据结构保存在内存中,因为没有必要关机之后持续保存这些数据。

参考资料:

https://github.com/moranzcw/Computer-Networking-A-Top-Down-Approach-NOTES

  • 9
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值