Loading

网络通信 : 粘包解决的实例 socketserver模块 udp的使用 简易版QQ的实现 异常处理机制的知识点

发送大文件(粘包问题的解决)

解决思路:

客户端:

  1.先获取一个文件夹下面的电影列表打印

  2.选择某个电影,得到具体的文件路径

  3.得到文件大小,去定义一个字典

  4.制作一个字典的报头,并发送

  5.发送字典

  6.发送电影的文件数据

服务端:

  1.先解析报头,得到字典的长度

  2.接收字典的字节数据,并还原成字典

  3.通过字典得到文件的长度

  4.进行循环接收,写入你自己的文件中

 1 #客户端:
 2 import socket
 3 import json
 4 import os
 5 import struct
 6 
 7 
 8 client = socket.socket()
 9 client.connect(('127.0.0.1',8080))
10 
11 while True:
12     # 获取电影列表 循环展示
13     MOVIE_DIR = r'F:\老男孩\上课内容\day01\视频'
14     movie_list = os.listdir(MOVIE_DIR)
15     # print(movie_list)
16     for i,movie in enumerate(movie_list, 1):
17         print(i, movie)
18     # 用户选择
19     choice = input('please choice movie to upload>>>:')
20     # 判断是否是数字
21     if choice.isdigit():
22         # 将字符串数字转为int
23         choice = int(choice) - 1
24         # 判断用户选择在不在列表范围内
25         if choice in range(0,len(movie_list)):
26             # 获取到用户想上传的文件路径
27             path = movie_list[choice]
28             # 拼接文件的绝对路径
29             file_path = os.path.join(MOVIE_DIR,path)
30             # 获取文件大小
31             file_size = os.path.getsize(file_path)
32             # 定义一个字典
33             res_d = {
34                 'file_name':'性感荷官在线发牌.mp4',
35                 'file_size':file_size,
36                 'msg':'注意身体,多喝营养快线'
37             }
38             # 序列化字典
39             json_d = json.dumps(res_d)
40             json_bytes = json_d.encode('utf-8')
41 
42             # 1.先制作字典格式的报头
43             header = struct.pack('i',len(json_bytes))
44             # 2.发送字典的报头
45             client.send(header)
46             # 3.再发字典
47             client.send(json_bytes)
48             # 4.再发文件数据(打开文件循环发送)
49             with open(file_path,'rb') as f:
50                 for line in f:
51                     client.send(line)
52         else:
53             print('not in range')
54     else:
55         print('must be a number')
56 #服务端:
57 import socket
58 import json
59 import struct
60 
61 
62 server = socket.socket()
63 server.bind(('127.0.0.1',8080))
64 server.listen(5)
65 
66 while True:
67     conn,addr = server.accept()
68     while True:
69         try:
70             header_len = conn.recv(4)
71             # 解析字典报头
72             header_len = struct.unpack('i',header_len)[0]
73             # 再接收字典数据
74             header_dic = conn.recv(header_len)
75             real_dic = json.loads(header_dic.decode('utf-8'))
76             # 获取数据长度
77             total_size = real_dic.get('file_size')
78             # 循环接收并写入文件
79             recv_size = 0
80             with open(real_dic.get('file_name'),'wb') as f:
81                 while recv_size < total_size:
82                     data = conn.recv(1024)
83                     f.write(data)
84                     recv_size += len(data)
85                 print('上传成功')
86         except ConnectionResetError as e:
87             print(e)
88             break
89     conn.close()
View Code

socketserver模块

服务端(server):

 1 import socketserver
 2 class Myserver(socketserver.BaseRequestHandler):
 3     def handle(self):
 4         self.data = self.request.recv(1024).strip()
 5         print("{} wrote:".format(self.client_address[0]))
 6         print(self.data)
 7         self.request.sendall(self.data.upper())
 8 
 9 if __name__ == "__main__":
10     HOST, PORT = "127.0.0.1", 9999
11 
12     # 设置allow_reuse_address允许服务器重用地址
13     socketserver.TCPServer.allow_reuse_address = True
14     # 创建一个server, 将服务地址绑定到127.0.0.1:9999
15     server = socketserver.TCPServer((HOST, PORT),Myserver)
16     # 让server永远运行下去,除非强制停止程序
17     server.serve_forever()
View Code

客户端(client):

 1 import socket
 2 
 3 HOST, PORT = "127.0.0.1", 9999
 4 data = "hello"
 5 
 6 # 创建一个socket链接,SOCK_STREAM代表使用TCP协议
 7 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
 8     sock.connect((HOST, PORT))          # 链接到客户端
 9     sock.sendall(bytes(data + "\n", "utf-8")) # 向服务端发送数据
10     received = str(sock.recv(1024), "utf-8")# 从服务端接收数据
11 
12 print("Sent:     {}".format(data))
13 print("Received: {}".format(received))
View Code

 

UDP使用:

UDP通信:

  数据报协议(自带报头)

  没有双向通道 通信类似于发短信

1.udp协议客户端允许发空
2.udp协议不会粘包
3.udp协议服务端不存在的情况下,客户端发送仍不会报错
4.udp协议支持并发

基本原理:

服务端(server):

 1 import socket
 2 
 3 
 4 server = socket.socket(type=socket.SOCK_DGRAM)  # UDP协议
 5 server.bind(('127.0.0.1',8080))
 6 # UDP不需要设置半连接池 它也没有半连接池的概念
 7 
 8 # 因为没有双向通道  不需要accept  直接就是通信循环
 9 while True:
10     data, addr = server.recvfrom(1024)
11     print('数据:',data)  # 客户端发来的消息
12     print('地址:',addr)  # 客户端的地址
13     server.sendto(data.upper(),addr)
View Code

客户端(client):

1 client = socket.socket(type=socket.SOCK_DGRAM)
2 # 不需要建立连接  直接进入通信循环
3 server_address = ('127.0.0.1',8080)
4 while True:
5     client.sendto(b'hello',server_address)
6     data, addr = client.recvfrom(1024)
7     print('服务端发来的数据',data)
8     print('服务端的地址',addr)
View Code

基于UDP实现的简易版QQ:

服务端:

 1 import socket
 2 
 3 
 4 server = socket.socket(type=socket.SOCK_DGRAM)
 5 server.bind(('127.0.0.1',8080))
 6 
 7 while True:
 8     data, addr = server.recvfrom(1024)
 9     print(data.decode('utf-8'))
10     msg = input('>>>:')
11     server.sendto(msg.encode('utf-8'),addr)
View Code

客户端(要设置多个):

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

udp和tcp的区别在于:

  udp没有粘包问题

异常处理机制的相关知识:

异常处理:

什么是异常?

  程序在运行过程中出现了不可预知的错误
  并且该错误没有对应的处理机制,那么就会以异常的形式表现出来
  造成的影响就是整个程序无法再正常运行

异常的结构:

  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.逻辑错误:
    这种错是可以被容忍的 因为一眼看不出来
    针对逻辑上的错误 可以采用异常处理机制进行捕获

常见的错误类型:

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

如何避免异常处理 ?

  在你认为可能会出现bug的代码块上方try一下。

  注意:try内部的代码块越少越好。
  try:

    ...

    可能出错的代码
  except 出错的类型 as e: # 将报错信息赋值给变量e
  出错之后的处理机制

    ...

 1 # res = {'name':''}
 2 # print(res['password'])
 3 # print(res.get('password','fdjdsfk'))
 4 
 5 # int('sdjajsd')
 6 # l = [1,2,3,4]
 7 # # l[111]
 8 
 9 
10 
11 # try:
12 #     name
13 #     l = [1,2,3]
14 #     l[111]
15 #     d = {'name':'jason'}
16 #     d['password']
17 # except NameError:
18 #     print('NameError')
19 # except IndexError:
20 #     print('indexerror')
21 # except KeyError:
22 #     print('keyerror')
23 """
24 错误发生之后  会立刻停止代码的运行
25 执行except语句 比对错误类型
26 """
27 
28 # try:
29 #     # name
30 #     # l = [1,2,3]
31 #     # l[111]
32 #     d = {'name':'jason'}
33 #     d['password']
34 #     # Exception
35 # except BaseException:  # 万能异常  所有的异常类型都被捕获
36 #     print('老子天下无敌')
37 
38 
39 
40 
41 
42 # try:
43 #     # name
44 #     l = [1,2,3]
45 #     l[111]
46 #     # d = {'name':'jason'}
47 #     # d['password']
48 # except Exception:  # 万能异常  所有的异常类型都被捕获
49 #     print('老子天下无敌')
50 # else:
51 #     print('被检测的代码没有任何的异常发生 才会走else')
52 # finally:
53 #     print('无论被检测的代码有没有异常发生 都会在代码运行完毕之后执行我')
54 
55 
56 # 主动抛异常
57 # if 'egon' == 'DSB':
58 #     pass
59 # else:
60 #     raise TypeError('尽说大实话')
61 # 关键字raise就是主动抛出异常
62 
63 
64 # l = [1,2,3]
65 # assert len(l) < 0  # 断言  预言
66 # 猜某个数据的状态 猜对了 不影响代码执行 正常走
67 # 猜错了  直接报错
68 
69 # 自定义异常
70 #9 自定义异常
71 class MyError(BaseException):
72      def __init__(self,msg):
73          super().__init__()
74          self.msg=msg
75      def __str__(self):
76          return '<dfsdf%ssdfsdaf>' %self.msg
77 
78 raise MyError('我自己定义的异常')  # 主动抛出异常其实就是将异常类的对象打印出来,会走__str__方法
View Code

并发:

看起来像同时运行的
并行:

真正意义上的同时运行

posted @ 2019-08-08 16:40  1640808365  阅读(305)  评论(0编辑  收藏  举报