Day29 网络编程(二) 大文件传输与UDP通信

1.基于TCP协议传输大文件

可以根据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('被我处理掉了')

异常处理的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')

主动抛出异常

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

断言

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

自定义异常

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('自定义的异常')

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协议允许发空

  2.UDP协议不会粘包

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

  4.UDP协议支持并发

基于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 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()  # 启动这个对象
服务端

猜你喜欢

转载自www.cnblogs.com/sxchen/p/11323456.html