[toc]
Socket编程
1 实验类型
验证型,2学时,必选实验
2 实验目的
掌握Socket编程中流套接字的技术;熟悉http消息结构;
3 实验内容与要求
使用Socket开发网络服务器,接收并保存请求原文;使用Socket开发网络客户端模拟浏览器向http服务器发送请求并记录响应结果;
4 实验环境
Microsoft Edge/Chrome/Firefox
等浏览器,Visual Studio Code
,Python 3.4+
,可用的互联网
步骤
- 创建工作目录
学号
,最终目录结构如下(包含创建的各类文件):
网络服务器
- 使用Socket技术编写网服务器(
request_server.py
),监听本机8080
端口,将网络请求原文保存名为req_1.txt
的文本文件,如:
request_server.py
import socket #导入socket模块
host = '127.0.0.1' #主机IP
port = 8080 #端口号
web = socket.socket() #创建 socket 对象
web.bind((host,port)) #绑定端口
web.listen(5) #设置最多连接数
print ('服务器等待客户端连接...')
req_index = 0 #请求序号
#开启死循环
while True:
conn, addr = web.accept() #建立客户端连接
data = conn.recv(1024) #获取客户端请求数据
print("{} connected!".format(addr))
#记录请求信息
req_index += 1
file_name = "req_{}.txt".format(req_index)
with open(file_name, 'w+', encoding='utf-8')as file:
file.write(data.decode())
#回应请求
conn.sendall(b'HTTP/1.1 200 OK\r\n\r\nHello World') #向客户端发送数据
conn.close() #关闭连接
Http请求分析
HTTP 请求和响应具有相似的结构,由以下部分组成︰ 一行起始行用于描述要执行的请求,或者是对应的状态,成功或失败。这个起始行总是单行的。 一个可选的 HTTP 头集合指明请求或描述消息正文。 一个空行指示所有关于请求的元数据已经发送完毕。 一个可选的包含请求相关数据的正文 (比如 HTML 表单内容), 或者响应相关的文档。正文的大小有起始行的 HTTP 头来指定。 起始行和 HTTP 消息中的 HTTP 头统称为请求头,而其有效负载被称为消息正文。
- 编写页面(
request.html
)模拟超链接
,表单
等形式的网络请求,如:
request.html
3. 在浏览器中打开步骤2中的页面,点击触发点向服务器发送请求
<html>
<body>
<!-- 超链接-->
<a href="http://127.0.0.1:8080" target="_blank">纯粹的链接</a><br>
<a href="http://127.0.0.1:8080/?name=ok&password=good" target="_blank">带参数的链接</a><br>
<a href="http://127.0.0.1:8080/?name=o k&password=goo d" target="_blank">带空格的链接</a><br>
<!--GET表单-->
<form name="GET表单" action="http://127.0.0.1:8080" method="GET" target="_blank">
<input type="text" name="name" value="ok"/>
<input type="password" name="password" value="good"/>
<input type="submit" value="提交"/>
</form>
<!--POST表单-->
<form name="POST表单" action="http://127.0.0.1:8080" method="POST" target="_blank">
<input type="text" name="name" value="ok"/>
<input type="password" name="password" value="good"/>
<input type="submit" value="提交"/>
</form>
<!--JS修改location-->
<script>
function jsonPack(){
var form = document.forms["JSON表单"];
var data = {
name: form["name"].value,
password: form["password"].value
};
form["all"].value = JSON.stringify(data);
}
</script>
<!--POST表单-->
<form name="JSON表单" action="http://127.0.0.1:8080" method="POST" target="_blank" onsubmit="jsonPack()">
<input type="hidden" name="all"/>
<input type="text" name="name" value="ok"/>
<input type="password" name="password" value="good"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
- 观察请求原文中消息结构并指出其中的差异
网络客户端
- 使用Socket开发网络客户端(
request_client.py
)模拟浏览器向http服务器发送请求并记录响应结果,如:
request_client.py
from datetime import datetime
import socket
from urllib.parse import urlparse
def get_url(url):
# 通过socket请求Url
url = urlparse(url)
host = url.hostname
path = url.path
port = url.port
if path == "":
path = "/"
if port is None:
port = 80
# 建立socket连接
client = socket.socket()
try:
print("{}:{} Connecting...".format(host, port))
client.connect((host, port))
except Exception as e:
print(e)
# 发送请求
client.send("GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n".format(path, host).encode('utf8'))
# 接收数据
recved = b""
while True:
bytes = client.recv(1024)
if bytes:
recved += bytes
else:
break
data = recved.decode('utf8')
# 记录响应信息
time_wall = datetime(2022, 7, 16)
elapsed = round((time_wall - datetime.now()).total_seconds())
file_name = "res_{}.txt".format(-elapsed)
with open(file_name, 'w+', encoding='utf-8')as file:
file.write(data)
client.close()
if __name__ == '__main__':
#get_url("http://www.baidu.com/")
get_url("http://127.0.0.1:8080/")
Http响应分析
- 观察响应原文中消息的结构