0
点赞
收藏
分享

微信扫一扫

计算机网络学习——套接字实验(二)

全栈学习笔记 2022-04-30 阅读 43

目录

实验三:邮件客户

实验四:多线程Web代理服务器


套接字(socket):可以理解其是在传输层和应用层之间的一个端点(或者一个开口),其形式上是socket = (ip,port),即该通信体的ip和端口号结合为socket,单个socket并不能完整的通信,它是一个端点,还需要通信对等体(peer)的socket,即两个socket连接起来完成通信过程。

实验三:邮件客户

电子邮件邮件系统有三部分组成:用户代理、邮件服务器和简单邮件传输协议(SMTP)。

  • 用户代理允许用户阅读、回复、转发、保存和撰写报文,发信人在用户代理上编辑邮件,并写清楚收件人的邮箱地址;用户代理根据发信人编辑的信息,生成—封符合邮件格式的邮件;用户代理把邮件发送到发信人的的邮件服务器上。
  • 邮件服务器上面有一个缓冲队列,发送到邮件服务器上面的邮件都会加入到缓冲队列中,等待邮件服务器上的客户端进行发送。
     
  • SMTP协议:简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)是一种提供可靠且有效电子邮件传输的协议,SMTP是建立在FTP文件传输服务上的一种邮件服务。SMTP协议定义了在两个或多个通信实体之间交换的报文的格式和顺序,以及报文发送或报文接收或其他事件采取的动作;即可以一对一发邮件也可以同时一对多发邮件。

实验要求:创建一个向任何接收方发送电子邮件的简单邮件客户:

  1. 你的客户必须与邮件服务器(如谷歌的电子邮件服务器)创建一个TCP连接;
  2. 使用SMTP协议与邮件服务器交谈;
  3. 经该邮件服务器向某接收方(如你的朋友)发送一个电子邮件报文,最后关闭与邮件服务器的TCP连接

从网站获取代码框架并运行:

import smtplib
from email.mime.text import MIMEText
from email.header import Header

mail_serve = 'smtp.qq.com'              #确定要建立TCP连接的邮件服务器,这里选qq邮箱
def get_mail_server(sender):            #构建方法筛选出目标邮件地址的名称
    key = sender[sender.index('@')+1:]  #查找寄信人地址中‘@’标识符并截取@后面内容
    return "smtp."+key                  #返回smtp格式的邮件服务器地址
  
port = '25'                             #smtp的默认端口号
sender = '257124xxx@qq.com'             #发件人邮箱地址
mail_server = get_mail_server(sender)
sender_pass = 'tcwfibsvyxxxxx'        #授权码,要在邮箱设置中获取授权码,不是登陆密码
receiver = '278120xxx@qq.com'           #收件人邮件地址
mail_msg = 'I make a simple e-mail client!'  #邮件内容

# 第一个参数是邮件正文内容
# 第二个是MIME类型,plain是指纯文本内容
# utf-8编码保证多语言兼容性
msg = MIMEText(mail_msg,'plain','utf-8')#建立MIMEText对象
msg['From'] = sender                    #定义发件人From,收信人To,也可以定义主题Subject
msg['To'] = receiver
#msg['Subject'] = Header('SMTP协议作业','utf-8')

try:
    server = smtplib.SMTP(mail_server,port) #通过服务器地址和端口号与邮件服务器建立连接
    server.login(sender,sender_pass)        #使用授权码登录
    server.sendmail(sender,(receiver),msg.as_string())  
    #发送邮件,(receiver)可以发多人因此传入一个list,邮件正文需要一个string类型,利用as_string()把MIMEText对象转为str
    server.quit()                           #关闭连接
    print("邮件发送成功")
except:
    server.quit()
    print("邮件发送失败")

运行结果:

 我们看抓包过程:筛选端口25(port 25)

 (动作1、2)首先看DNS寻址内容:

  • 本机地址——>192.168.31.1(我使用的小米路由器IP):Standard query :smtp.qq.com,请求路由器解析域名smtp.qq.com的IP地址
  • 192.168.31.1——>本机地址:Standard query response:120.241.186.96返回查询到的域名地址

此外从传输协议中可见此次传输使用的是UDP协议。

 

 展开DNS使用UDP和TCP的内容:

(动作3、4、5)DNS后是TCP协议的客户端和QQ邮箱服务器的三次握手,三次握手建立连接后,开始进行SMTP传输。

看SMTP的传输过程:

(动作6)邮件服务器响应220,建立连接成功,服务就绪:

 (动作7)客户端继续发送请求ehlo(或HELO),并在后面附带本机IP地址,即告诉服务器客户端的名称。EHLO和HELO命令的区别在于EHLO带身份验证而HELO不带。

(动作8)服务器使用TCP返回确认收到客户端IP地址的应答。

(动作9)服务器返回250表示请求动作完成,并告诉客户端使用AUTH LOGIN验证方式登录。

(动作10)客户端给服务器发送AUTH LOGIN验证码。

 动作12服务器返回235表示认证通过;动作13客户端请求FROM指令,发送发件人地址;数据传输完成后,动作19服务器返回250 ok;动作20客户端请求rcpt指令,发送收信人地址;动作23客户端请求data指令,准备发送邮件内容;动作25,服务器告知客户端发送开始,并以<CR><LF>.<CR><LF>.结束,客户端收到354响应后开始传输;动作26包含了要发件人、收件人、内容等数据。

动作32传输完成后,服务器返回250 ok queued as,表示请求动作完成,并在排队等候下一个请求;动作33客户端返回quit,表示断开SMTP连接;服务器返回221 bye,表示处理断开连接中。最后客户端发起四次挥手断开TCP连接。

经过简单的分析可以知道,SMTP作为处理邮件传输的协议,它属于明显的请求应答式协议,即一问一答,客户端发送指令,服务器应答,过程中产生的数据传输需要使用数据传输协议TCP或者UDP进行传输。并且从抓包过程中的数据分析,SMTP的传输内容是可以被捕获并可见,因此日常使用SMTP协议还需进行安全保证,如使用SSL协议加密等。

实验四:多线程Web代理服务器

研发一个简单的Web代理服务器,要求:

  • 当你的代理服务器从一个浏览器接收到对某对象的HTTP请求,它生成对相同对象的一个新HTTP请求并向初始服务器发送;
  • 当该代理服务器从初始服务器接收到具有该对象的HTTP响应时,它生成一个包括该对象的新HTTP响应,并发送给该客户;
  • 这个服务器是多相处的,使其在相同时间能处理多个请求。

代理服务器(Proxy Server):大多被用来连接国际互联网和局域网,具有一定的安全功能,比如它可以帮我们不断在互联网上更换IP地址,还可以在数据传输时进行加密;它将我们平时使用网络浏览器直接请求目标服务器的过程分为两步,即客户端先请求代理服务器,由代理服务器去取回客户端的请求内容,然后返回给客户端,这起到了一定的安全防护作用,但无疑增加了许多资源消耗和时间消耗。与此同时,代理服务器也有属于它的缓存区,类似一个大的cache,它不断获取内容缓存在服务器中,当客户端再次请求时,直接传给客户端,节省消耗。

        代理服务器也分几种类型,目前流行的有SOCKS代理和HTTP代理;SOCKS代理比传统的HTTP代理更广泛。SOCKS位于传输层上的TCP和UDP(基本上处理所有数据传输的协议)之上。这意味着它可以与客户端和服务器形成物理连接,以尝试确保所有数据包都以与发送相同的方式到达其预期目的地。

      但HTTP 和 HTTPS 仍然是最受欢迎的代理。使用 HTTP 代理的主要目的是组织浏览器和其他依赖 TCP 协议的程序的工作。 HTTP 和 HTTPS 代理以非常简单的方式工作。在这种情况下,该程序是浏览器向代理服务器发送打开特定资源 (URL) 的请求。然后,服务器接收数据并将其发送到您的浏览器。HTTP 与 HTTPS 之间的区别在于,前者是非安全代理,而后者是安全代理。 

        SOCKS 是 Socket Secure 的缩写,是一种网络协议,通过防火墙路由网络流量,从而促进与服务器的通信。 SOCKS 与 HTTP/HTTPS 不同,它不调整 HTTP 标头,服务器将通过自己传输数据而不会更改任何内容。今天,SOCKS 是最先进的数据传输协议,专门为不支持直接使用代理的程序量身定制。 这些是使用标准端口 1080 和 1081 的程序。SOCKS 代理已经从最初的 SOCKS 发展到 SOCKS4 和最新的 SOCKS5。 

实验代码(未完善):

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)
# Create a server socket, bind it to a port and start listening
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerPort = int(sys.argv[1])
tcpSerSock.bind(("", 8888))            #绑定代理服务器的IP和端口号
print(tcpSerPort)
tcpSerSock.listen(10)
while 1:
	print('Ready to serve...')         #创建socket连接,接收浏览器传输的数据
	tcpCliSock, addr = tcpSerSock.accept()
	print('Received a connection from:', addr)
	message = tcpCliSock.recv(1024)
	message = message.decode()
	print("message:", message)
	if(message == ''):
		continue
	# Extract the filename from the given message
	print("message.split()[1]:", message.split()[1])
	filename = message.split()[1].partition("/")[2]          #提取请求的文件名
	print("filename:", filename)
	fileExist = "false"
	filetouse = "/" + filename
	print("filetouse:", filetouse)
	try:													
		 #判断代理服务器缓存是有该文件,有则直接从cache中获取
		f = open("WEB/" + filetouse[1:], "rb")
		outputdata = f.read()
		f.close()
		fileExist = "true"
		# ProxyServer finds a cache hit and generates a response message
		tcpCliSock.send("HTTP/1.1 200 OK\r\n".encode())      #返回报文和数据
		tcpCliSock.send("Content-Type:text/html\r\n\r\n".encode())
		tcpCliSock.send(outputdata)
		print('Read from cache')
	# Error handling for file not found in cache
	except IOError:											 #从网站请求
		if fileExist == "false":
			# Create a socket on the proxyserver
			c = socket(AF_INET, SOCK_STREAM)
			hostn = filename.replace("www.","",1)
			print("hostn:", hostn)
			try:
				# Connect to the socket to port 80
				serverName = hostn.partition("/")[0]
				#serverName = c.gethostbyname(filename)  
				serverPort = 80
				print((serverName, serverPort))
				c.connect((serverName, serverPort))
				askFile = ''.join(filename.partition('/')[1:])
				print("askFile:", askFile)
				# Create a temporary file on this socket and ask port 80
				# for the file requested by the client
				fileobj = c.makefile('rwb', 0)
				fileobj.write("GET ".encode() + askFile.encode() + " HTTP/1.0\r\nHost: ".encode() + serverName.encode() + "\r\n\r\n".encode())
				# Read the response into buffer
				serverResponse = fileobj.read()
				# 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
				filename = "WEB/" + filename
				filesplit = filename.split('/')
				for i in range(0, len(filesplit) - 1):
					if not os.path.exists("/".join(filesplit[0:i+1])):
						os.makedirs("/".join(filesplit[0:i+1]))
				tmpFile = open(filename, "wb")
				print(serverResponse)
				serverResponse = serverResponse.split(b'\r\n\r\n')[1]
				print(serverResponse)
				tmpFile.write(serverResponse)
				tmpFile.close()
				tcpCliSock.send("HTTP/1.1 200 OK\r\n".encode())
				tcpCliSock.send("Content-Type:text/html\r\n\r\n".encode())
				tcpCliSock.send(serverResponse)
			except:
				print("Illegal request")
			c.close()
		else:
			# HTTP response message for file not found
			print("NET ERROR")
	# Close the client and the server sockets
	tcpCliSock.close()
tcpSerSock.close()

报文和抓包跟实验一的web服务器一致,这是客户端请求代理服务器时,代理服务器将该文件缓存下来的响应过程。

目前存在问题:我还没实现将浏览器请求的非本地文件的部分完善,比如请求域名和其他服务器的文件,一个是将域名通过DNS转为目标IP地址,但我还不会与该服务器建立连接获取文件(会被阻挡反爬虫)这应该类似网络爬虫的内容,我有待学习;第二我还无法在局域网建立一个目标服务器让我连接,来请求文件,这个主要是我只有手上一台电脑。因此本实验进度拖延了!

 

举报

相关推荐

0 条评论