今日内容
1,作业:实现用户循环上传电影
2,异常处理
3,UDP通信
4,SocketServer
1,作业:
客户端:
import os
import struct
import socket
import json
client = socket.socket()
client.connect(('127.0.0.1', 1688))
while True:
# 获取文件的绝对路径
MOVIE_PATH = r'D:\预习视频\day12\视频'
# 获取电影列表目录
movie_list = os.listdir(MOVIE_PATH)
# 循环打印电影列表
for i, movie in enumerate(movie_list):
print(i, movie)
# 让用户选择 电影列表编号
choice = input('请输入商品编号:').strip()
if choice.isdigit():
choice = int(choice)
if choice in range(0, len(movie_list)):
# 获取用户选择的电影路径
path = movie_list[choice]
# 拼接电影的绝对路径
path_dir = os.path.join(MOVIE_PATH,path)
# 获取文件大小
file_size = os.path.getsize(path_dir)
# 创建一个字典
d = {'name':'爱你一生千百惠.mp4', 'file_size': file_size, 'ps': '喝酒别开车!'}
# 对该字典进行序列化
json_dict = json.dumps(d)
# 把序列化后的字符串转化为二进制数据
dict_bytes = json_dict.encode('utf-8')
# 创建字典报头
header = struct.pack('i', len(dict_bytes))
# 发送字典报头
client.send(header)
# 发送字典
client.send(dict_bytes)
# 循环发送真实的文件数据
with open(path_dir, 'rb')as f:
for line in f:
client.send(line)
else:
print('选择不在范围之内')
else:
print('请选择数字!')
服务端:
import struct
import socket
import json
server = socket.socket()
server.bind(('127.0.0.1', 1688))
server.listen(5)
while True:
conn, addr = server.accept()
while True:
try:
# 接受报的规定长度
header_len = conn.recv(4)
# 先解析字典的报头
header_len = struct.unpack('i',header_len)[0]
# 接受字典
header_dict = conn.recv(header_len)
# 把接受到的二进制数据反序列化成json格式字典
dict_json = json.loads(header_dict.decode('utf-8'))
# 从字典中获取文件大小
file_size = dict_json.get('file_size')
# 循环接受并写入文件
recv_size = 0
# 在这里获取的是字典的名字
with open(dict_json.get('name'), 'wb')as f:
while recv_size < file_size:
data = conn.recv(1024)
# 读出来1024个字节的数据就将它写入文件
f.write(data)
# 直到写入文件的数据全部为被接受完的数据 ******************
recv_size+=len(data)
except ConnectionResetError as e:
print(e)
break
conn.close()
2:异常处理
什么是异常?
程序在运行过程中出现了不可预知的错误
并且该错误没有对应的处理机制,那么就会以异常的形式表现出来
造成的影响就是整个程序无法再正常运行
异常的结构
1.异常的类型:NAMEERROR
2.异常的信息:name 'fdsdfsdf' is not defined
3.异常的位置:Traceback (most recent call last):
File "D:/python脱产10期视频/day29/01 异常处理.py", line 1, in <module>
fdsdfsdf
异常的种类
分为两大类
1.语法错误
是你程序立刻就能解决的,这种错误是不能被容忍的
语法上的错误 发现之后应该立刻解决
2.逻辑错误 ****
这种错是可以被容忍的 因为一眼看不出来
针对逻辑上的错误 可以采用异常处理机制进行捕获,用try,except
ps: except 后面跟错误类型
常见的错误类型
NAMERROR 名字错误 **********
SyntaxError 语法错误 **********
KeyError 键不存在 **********
ValueError 值错误 **********
IndexError 索引错误 **********
try:
name
l = [1,2,3]
l[111]
d = {'name':'jason'}
d['password']
except NameError:
print('NameError')
except IndexError:
print('indexerror')
except KeyError:
print('keyerror')
ps:1,错误发生后,会立刻停止代码的运行,
2,会走第一个except,只要出错。下面的except都不会走
3,except BaseException: # 万能异常 所有的异常类型都被捕获
Exception也是万能异常,他继承了BaseException
如何避免
异常处理
在你认为可能会出现bug的代码块上方try一下:注意try内部的代码块越少越好 *****
try:
可能出错的代码
except 出错的类型 as e: # 将报错信息赋值给变量e
出错之后的处理机制 ================================
try:
# name
l = [1,2,3]
l[111]
# d = {'name':'jason'}
# d['password']
except Exception: # 万能异常 所有的异常类型都被捕获
print('老子天下无敌')
else:
print('被检测的代码没有任何的异常发生 才会走else')
finally:
print('无论被检测的代码有没有异常发生 都会在代码运行完毕之后执行
主动抛异常
if 'egon' == 'DSB':
pass
else:
raise TypeError('尽说大实话')
关键字raise就是主动抛出异常
l = [1,2,3]
assert len(l) < 0 # 断言 预言
猜某个数据的状态 猜对了 不影响代码执行 正常走
猜错了 直接报错
l = [1,2,3]
assert len(l) < 0 # 断言 预言
猜某个数据的状态 猜对了 不影响代码执行 正常走
猜错了 直接报错
自定义异常
9 自定义异常
class MyError(BaseException):
def __init__(self,msg):
super().__init__()
self.msg=msg
def __str__(self):
return '<dfsdf%ssdfsdaf>' %self.msg
raise MyError('我自己定义的异常') # 主动抛出异常其实就是将异常类的对象
3,UDP 协议
1,udp 不会粘包,因为他是数据报协议,自带报头
2,不需要建立链接,直接进行发送数据,没有双向通道,就像发送短信一样
3,当服务端不存在时 ,也不会报错,客户端允许发空
客户端:
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1',1688)
while True:
client.sendto(b'fggfgfghyhjh',server_addr)
data, addr = client.recvfrom(1024)
print('服务端发来的数据',data)
print('服务端的地址',addr)
服务端:
import socket
server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 1688))
# udp 不需要设置半连接池,没有链接池这个概念
# 没有双向通道,所以不需要accept ,直接通信循环
while True:
data, addr = server.recvfrom(1024) 接受数据
print('数据', data) # 客户端发来的数据
print(addr) # 客户端的ip地址和端口
server.sendto(data.lower(),addr) 发送数据 # 数据和地址
简易版本的qq案例:
服务端:
import socket
server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 1688))
while True:
data, addr = server.recvfrom(1024)
print(data.decode('utf-8'))
msg = input('>>>>:')
server.sendto(msg.encode('utf-8'),addr)
客户端:
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1', 1688)
while True:
msg = input('>>>>:')
msg = '来自客户端0的数据:%s'% msg
client.sendto(msg.encode('utf-8'),server_addr)
data, addr = client.recvfrom(1024)
print(data.decode('utf-8'))
4,SocketServer(让tcp支持并发,也可支持UDP)
客户端:
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
client.send(b'hello')
data = client.recv(1024)
print(data.decode('utf-8'))
服务端:
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
while True:
data = self.request.recv(1024)
print(self.client_address)
print(data.decode('utf-8'))
self.request.send(data.upper())
if __name__ == '__main__':
# 创建一个tcp对象
server = socketserver.ThreadingTCPServer(('127.0.0.1',1688),MyServer)
server.serve_forever()