网络编程(三) 大文件传输与UDP通信 1.基于TCP协议传输大文件 2.异常处理 3.基于UDP通信的socket 4.SocketServer模块

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

可以根据TCP粘包问题的处理方法实现大文件的传输

上传大文件

 1 import socket
 2 import os
 3 import struct
 4 import json
 5 
 6 client = socket.socket()
 7 client.connect(('127.0.0.1',8080))
 8 
 9 while True:
10     MOVIE_DIR = r'F:迅雷下载'
11     movie_list = os.listdir(MOVIE_DIR)
12     for i,movie in enumerate(movie_list,1):
13         print(i,movie)
14     choice = input('>>>:').strip()
15     if not choice.isdigit():
16         print('请输入数字')
17         continue
18     choice = int(choice)-1
19     if choice not in range(0,len(movie_list)):
20         print('请输入正确的编号')
21         continue
22     movie_name = movie_list[choice]
23     movie_path = os.path.join(MOVIE_DIR,movie_name)
24     size = os.path.getsize(movie_path)
25     # 生成一个字典
26     d = {'name':movie_name,'size':size,'path':movie_path}
27     json_d = json.dumps(d)
28     # 生成一个字典报头
29     header = struct.pack('i',len(json_d))
30     # 发送字典报头
31     client.send(header)
32     # 发送字典
33     client.send(json_d.encode('utf-8'))
34     # 发送真实数据
35     with open(movie_path,'rb')as f:
36         for line in f:
37             client.send(line)
38     print('上传成功')
客户端
 1 import socket
 2 import struct
 3 import json
 4 import os
 5 
 6 server = socket.socket()
 7 server.bind(('127.0.0.1',8080))
 8 server.listen(5)
 9 
10 while True:
11     conn, addr = server.accept()
12     while True:
13         try:
14             # 接收报头
15             header = conn.recv(4)
16             dict_len = struct.unpack('i',header)[0]
17             # 接收字典
18             d = conn.recv(dict_len).decode('utf-8')
19             dict = json.loads(d)
20             # 字典中取出数据
21             movie_name = dict.get('name')
22             movie_size = dict.get('size')
23             save_path = os.path.join(movie_name)
24             recv_size = 0
25             # 接收真实数据
26             with open(save_path,'wb')as f:
27                 while recv_size < movie_size:
28                     data = conn.recv(1024000000)
29                     f.write(data)
30                     recv_size += len(data)
31                     c = recv_size / movie_size
32                     d = "%.2f%%" % (c * 100)
33                     print(d)
34             print('接收上传完毕')
35         except ConnectionResetError as e:
36             print(e)
37             break
38     conn.close()
服务端

下载大文件

 1 import socket
 2 import json
 3 import struct
 4 
 5 client = socket.socket()
 6 client.connect(('127.0.0.1',8080))
 7 
 8 while True:
 9     # 接收列表的报头
10     list_header = client.recv(4)
11     # 解包获取列表的长度
12     list_len = struct.unpack('i',list_header)[0]
13     # 接收列表
14     movie_json = client.recv(list_len).decode('utf-8')
15     movie_list = json.loads(movie_json)
16     for i,movie in enumerate(movie_list,1):
17         print(i,movie)
18     choice = input('>>>:').strip()
19     if not choice.isdigit():
20         print('请输入数字')
21         continue
22     choice = int(choice) - 1
23     if choice not in range(0,len(movie_list)):
24         print('请输入正确的编号')
25         continue
26     # 发送选择
27     client.send(str(choice).encode('utf-8'))
28     # 接收报头
29     dict_header = client.recv(4)
30     # 解包获取字典长度
31     dict_len = struct.unpack('i',dict_header)[0]
32     # 接收字典
33     d = client.recv(dict_len).decode('utf-8')
34     movie_dict = json.loads(d)
35     # 获取字典中的信息
36     movie_name = movie_dict.get('name')
37     movie_size = movie_dict.get('size')
38     recv_size = 0
39     # 接收真实数据
40     with open(movie_name,'wb')as f:
41         while recv_size < movie_size:
42             data = client.recv(1024)
43             f.write(data)
44             recv_size += len(data)
45             c = recv_size/movie_size
46             d = "%.2f%%" % (c * 100)
47             print(d)
48     print('下载成功')
客户端
 1 import json
 2 import socket
 3 import os
 4 import struct
 5 
 6 
 7 server = socket.socket()
 8 server.bind(('127.0.0.1',8080))
 9 server.listen()
10 
11 while True:
12     conn, addr = server.accept()
13     while True:
14         try:
15             MOVIE_DIR = r'F:迅雷下载'
16             # 生成电影列表
17             movie_list = os.listdir(MOVIE_DIR)
18             movie_json = json.dumps(movie_list)
19             list_header = struct.pack('i',len(movie_json))
20             # 发送列表的报头
21             conn.send(list_header)
22             # 发送列表
23             conn.send(movie_json.encode('utf-8'))
24             # 接收选择
25             choice = conn.recv(1024).decode('utf-8')
26             choice = int(choice)
27             movie_name = movie_list[choice]
28             # 获取电影的信息,生成字典
29             movie_path = os.path.join(MOVIE_DIR,movie_name)
30             size = os.path.getsize(movie_path)
31             d = {'name':movie_name,'size':size}
32             # 制作电影的报头
33             dict = json.dumps(d)
34             dict_header = struct.pack('i',len(dict))
35             # 发送报头
36             conn.send(dict_header)
37             # 发送字典
38             conn.send(dict.encode('utf-8'))
39             # 发送真实数据
40             with open(movie_path,'rb')as f:
41                 for line in f:
42                     conn.send(line)
43             print('发送完成')
44         except ConnectionResetError as e:
45             print(e)
46             break
47     conn.close()
服务端

2.异常处理

什么是异常

  异常就是程序在运行过程中出现了不可预知的错误

  并且该错误没有对应的处理机制,会以异常的形式表现出来

  造成的影响就是整个程序无法再正常运行

异常的结构

  1.异常的类型:NAMEERROR

  2.异常的信息:name 'fdsdfsdf' is not defined

  3.异常的位置:Traceback (most recent call last):后面跟的就是出现异常的位置,点击就能自动找到该位置

异常的种类,分为两大类

  1.语法错误:

    这种是运行程序立刻就能发现的,发现之后可以立刻解决

  2.逻辑错误

    这种错误一眼并不能看出来,针对这种错误,我们可以使用异常处理机制来捕获

常见的错误类型: 

  NAMERROR 名字错误
  SyntaxError 语法错误
  KeyError 键不存在
  ValueError 值错误
  IndexError 索引错误

如何避免

  异常处理:

    在会出现异常代码块上方try一下.注意:try内部的代码块越少越好

  语法:

1 try:
2     # 可能出现错误的代码块
3 except 错误的类型 as e:  # 将错误的信息赋值给变量e
4     # 出错之后的代码块

万能异常处理Exception和BaseException

 1 # 两个万能异常处理Exception和BaseException
 2 try:
 3     l = [1,2,3]
 4     l[123]
 5 except Exception as e:
 6     print(e)
 7     print('被我处理掉了')
 8 
 9 try:
10     d = {'name':'sxc'}
11     d['pwd']
12 except BaseException as e:
13     print(e)
14     print('被我处理掉了')

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

异常处理的else和finally

 1 # else和finally
 2 try:
 3     d = {'name':'sxc'}
 4     d['name']
 5 except BaseException as e:
 6     print(e)
 7     print('被我处理掉了')
 8 else:
 9     print('没有出错就会走else')
10 finally:
11     print('不管有没有出错都会走finally')

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

主动抛出异常

1 # 主动抛出异常
2 if 1 > 2:  # 异常判断条件
3     pass
4 else:
5     raise TypeError('不存在的')  # raise + TypeError + 异常信息

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

断言

1 # 断言,预言
2 l = [1,2,3]
3 assert l[0] < 0

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

自定义异常

1 # 自定义异常
2 class MyError(BaseException):
3     def __init__(self,msg):
4         super().__init__()
5         self.msg = msg
6     def __str__(self):
7         return '<%s>' %self.msg
8 
9 raise MyError('自定义的异常')

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

3.基于UDP通信的socket

  又称数据包协议,UDP协议是无连接的,启动之后可以直接接收消息,不需要提前建立连接,类似于发短信

UDP通信socket的简单使用

 1 import socket
 2 import time
 3 
 4 client = socket.socket(type=socket.SOCK_DGRAM)
 5 server_addr = ('127.0.0.1',8080)
 6 
 7 while True:
 8     client.sendto(b'hello',server_addr)
 9     data,addr = client.recvfrom(1024)
10     print(data)
11     print(addr)
客户端
 1 import socket
 2 
 3 server = socket.socket(type=socket.SOCK_DGRAM)
 4 server.bind(('127.0.0.1',8080))
 5 # 面向连接的不需要半连接池,也不需要建立双向通道
 6 while True:
 7     data, addr = server.recvfrom(1024)
 8     print(data)
 9     print(addr)
10     server.sendto(data.upper(),addr)
服务端

UDP通信和TCP通信的区别

  1.UDP协议允许发空

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

  2.UDP协议不会粘包

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

  3.UDP协议服务端不存在的情况下.客户端不会报错

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

  4.UDP协议支持并发

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

基于UDP实现一个简易版本的QQ

 1 import socket
 2 
 3 server = socket.socket(type=socket.SOCK_DGRAM)
 4 server.bind(('127.0.0.1',8080))
 5 
 6 while True:
 7     data ,addr = server.recvfrom(1024)
 8     print(data.decode('utf-8'))
 9     msg = input('>>>:')
10     server.sendto(msg.encode('utf-8'),addr)
服务端
 1 import socket
 2 
 3 client = socket.socket(type=socket.SOCK_DGRAM)
 4 server_addr = ('127.0.0.1',8080)
 5 
 6 while True:
 7     msg = input('>>>:')
 8     msg1 = '来自客户端1的消息%s'%msg
 9     client.sendto(msg1.encode('utf-8'),server_addr)
10     data,addr = client.recvfrom(1024)
11     print(data.decode('utf-8'))
客户端

如需要多个客户通信,只要多开几个客户端就行了

4.SocketServer模块

可以实现TCP/UDP并发通信

TCP并发通信

1 import socket
2 
3 client = socket.socket()
4 client.connect(('127.0.0.1',8080))
5 
6 while True:
7     client.send(b'hello')
8     data = client.recv(1024)
9     print(data.decode('utf-8'))
客户端
 1 import socketserver
 2 
 3 class MyServer(socketserver.BaseRequestHandler):
 4     def handle(self):
 5         while True:
 6             data = self.request.recv(1024)
 7             print(self.client_address)  # 客户端地址
 8             print(data.decode('utf-8'))
 9             self.request.send(data.upper())
10 
11 
12 if __name__ == '__main__':
13     # 当有客户端来连接会自动交给自定义类中的handle方法处理
14     server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer)  # 创建一个基于TCP的对象
15     server.serve_forever()  # 启动这个对象
服务端

网络编程(三) 大文件传输与UDP通信
1.基于TCP协议传输大文件
2.异常处理
3.基于UDP通信的socket
4.SocketServer模块

UDP并发通信

 1 import socket
 2 import time
 3 
 4 client = socket.socket(type=socket.SOCK_DGRAM)
 5 server_addr = ('127.0.0.1',8080)
 6 
 7 while True:
 8     client.sendto(b'hello',server_addr)
 9     data,addr = client.recvfrom(1024)
10     print(data.decode('utf-8'),addr)
11     time.sleep(1)
客户端
 1 import socketserver
 2 
 3 class MyServer(socketserver.BaseRequestHandler):
 4     def handle(self):
 5         while True:
 6             data,sock = self.request
 7             print(self.client_address)  # 客户端地址
 8             print(data.decode('utf-8'))
 9             sock.sendto(data.upper(),self.client_address)
10 
11 
12 if __name__ == '__main__':
13     # 当有客户端来连接会自动交给自定义类中的handle方法处理
14     server = socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyServer)  # 创建一个基于UDP的对象
15     server.serve_forever()  # 启动这个对象
服务端

 29