UDP套接字广播
- 广播定义:一端发送多点接收
- 广播地址:每个网络的最大地址为发送广播的地址,向该地址发送,则网段内所有主机都能接收。
广播发送(broadcast_send.py):
from socket import *
from time import sleep
# 广播地址
dest = ('192.168.0.101', 9999)
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, True)
data = '发送的广播信息'
while True:
sleep(2)
s.sendto(data.encode(), dest)
s.close()
广播接收(broadcast_recv.py):
from socket import *
s=socket(AF_INET, SOCK_DGRAM)
# 让套接字可以接收广播
s.setsockopt(SOL_SOCKET, SO_BROADCAST, True)
s.bind(('0.0.0.0', 9999))
while True:
try:
msg, addr = s.recvfrom(1024)
except KeyboardInterrupt:
break
else:
print(msg.decode())
s.close()
TCP套接字之HTTP传输
HTTP协议(超文本传输协议)
- 用途:网页获取,数据的传输
- 特点:
- 应用层协议,传输层使用tcp传输
- 简单,灵活,很多语言都有HTTP专门接口
- 无状态,协议不记录传输内容
- http1.1 支持持久连接,丰富了请求类型
- 网页请求过程
【1】客户端(浏览器)通过tcp传输,发送http请求给服务端
【2】服务端接收到http请求后进行解析
【3】服务端处理请求内容,组织响应内容
【4】服务端将响应内容以http响应格式发送给浏览器
【5】浏览器接收到响应内容,解析展示
HTTP请求(request)
- 请求行(重点):具体的请求类别和请求内容
GET / HTTP/1.1
请求类别 请求内容 协议版本
- 请求类别:每个请求类别表示要做不同的事情,包括:
【1】GET:获取网络资源
【2】POST:提交一定的信息,得到反馈
【3】HEAD:只获取网络资源的响应头(对请求资源的说明)
【4】PUT:更新服务器资源
【5】DELETE:删除服务器资源
【6】CONNECT(无具体功能)
【7】TRACE:测试
【8】OPTIONS:获取服务器性能信息 - 请求内容:可以类比文件目录。/ 表示主页,/XXX 表示主页下的具体内容
- 协议版本:HTTP1.0/1.1(现在都用1.1)
- 请求头:对请求的进行一步解释和描述
Accept-Encoding:gzip(希望得到的编码格式) - 空行
- 请求体:请求的参数或者提交的内容
HTTP响应(response)
响应格式:响应行,响应头,空行,响应体
- 响应行:反馈基本的响应情况
HTTP/1.1 200 OK
版本信息 响应码 附加信息
响应码:
1XX:提示信息,表示请求被接受
2XX:响应成功 200
3XX:响应需要进一步操作,重定向
4XX:客户端错误 404
5XX:服务器错误
- 响应头:对响应内容的描述
Content-Type:text/html - 空行
- 响应体:响应的主体内容信息
模拟浏览器向服务器发送请求,服务器将响应结果发送给浏览器,并渲染浏览器页面。
服务器代码:
'''
服务端代码
'''
from socket import *
sockfd=socket()
sockfd.bind(('0.0.0.0', 8000))
sockfd.listen(5)
connfd, addr = sockfd.accept()
print('Connect from:', addr)
data = connfd.recv(1024) # 模拟接收请求
print(data.decode())
data="""HTTP/1.1 200 OK
Content-Type:text/html
<h1>hello world</h1>
"""
connfd.send(data.encode()) # 模拟发送响应信息
connfd.close()
sockfd.close()
在浏览器(客户端)地址栏输入请求URL:http://127.0.0.1:8000/(请求内容为空),请求结果如下:
服务器得到请求结果,并将响应结果发送回浏览器,浏览器解析HTML格式内容,并渲染页面如下:
如果对上述响应内容(data)不想固定,而是读取HTML文件方式,可以参考我上传的文件。
struct模块的使用
- 原理:将一组简单数据进行打包,转换为bytes格式发送。或者将一组bytes格式数据,进行解析。
- 接口使用
Struct(fmt)
功能:生成结构化对象
参数:fmt 定制的数据结构
st.pack(v1,v2,v3…)
功能:将一组数据按照指定格式打包转换为bytes
参数:要打包的数据
返回值:bytes字节串
st.unpack(bytes_data)
功能:将bytes字节串按照指定的格式解析
参数:要解析的字节串
返回值:解析后的内容
bytes_data = struct.pack(fmt,v1,v2,v3…)
d = struct.unpack(fmt,bytes_data)
说明:可以使用struct模块直接调用pack unpack。此时这两函数第一个参数为fmt,其余功能相同。
示例代码:
import struct
# 以传递 1(int) zhangsan(8个string) 16(int) 78.5(float) 为例
# 打包
st = struct.Struct("i8sif")
data = st.pack(1, b'zhangsan', 16, 78.5)
print(data)
# b'\x01\x00\x00\x00zhangsan\x10\x00\x00\x00\x00\x00\x9dB'
# 解包
d = st.unpack(data)
print(d)
# (1, b'zhangsan', 16, 78.5)
数据结构转换码:
小练习:
- 从客户端输入一个学生的 id 姓名 年龄 分数
- 将其发送到服务器,有服务端写入到一个文件中
- 每个信息占一行
- 数据传输使用udp完成
客户端代码:
from socket import *
import struct
sockfd = socket(AF_INET, SOCK_DGRAM) # 数据报套接字
# 定制数据结构
st = struct.Struct("i32sif")
id = 1
while True:
name = input('姓名>>').encode()
age = int(input('年龄>>'))
score = float(input('分数>>'))
data = st.pack(id, name, age, score) # 数据打包
if not name or not age or not score:
break
sockfd.sendto(data, ('127.0.0.1', 8000)) # 发送数据
id += 1
msg, addr = sockfd.recvfrom(1024)
print('From server:', msg.decode())
sockfd.close()
服务端代码:
from socket import *
import struct
sockfd = socket(AF_INET, SOCK_DGRAM) # 数据报套接字
sockfd.bind(('0.0.0.0', 8000)) # 绑定地址
# 定制数据结构
st = struct.Struct("i32sif")
while True:
data, addr = sockfd.recvfrom(1024)
d = st.unpack(data)
print(d) # (1, b'zhangsan', 16, 78.5)
f = open('demo.txt', 'a+')
f.write('%d %s %d %.1f\n' % (d[0], d[1].decode(), d[2], d[3]))
f.flush()
sockfd.sendto(b'OK', addr)
f.close()
sockfd.close()
网络编程部分总结
需要掌握:
- 文件的读写操作(重要)
- 网络通信的基本知识
- TCP和UDP的通信(重要)
- http协议基础(重要)
- struct模块使用