zoukankan      html  css  js  c++  java
  • 网络通信 : 粘包解决的实例 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 + "
    ", "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

    并发:

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

    真正意义上的同时运行

  • 相关阅读:
    如何快速、低成本构建一套稳定、高效、可靠的互联网主播直播/商业直播(推流/分发/播放)方案
    EasyNVR H5无插件RTSP直播方案在Windows server 2012上修复无法定位GetNumaNodeProcessorMaskEx的问题
    EasyNVR H5无插件RTSP直播方案在Windows server 2012上修复无法定位GetNumaNodeProcessorMaskEx的问题
    EasyPusher RTSP推流/EasyRTMP RTMP推流Android安卓摄像头视频偏暗的问题解决方案
    EasyPusher RTSP推流/EasyRTMP RTMP推流Android安卓摄像头视频偏暗的问题解决方案
    EasyPlayer RTSP Android安卓播放器修复播放画面卡在第一帧bug
    Ubuntu14.04下安装eclipse
    UBuntu14.04下安装和卸载Qt5.3.1
    ubuntu创建、删除文件及文件夹,强制清空回收站方法
    Ubuntu下安装JDK1.7
  • 原文地址:https://www.cnblogs.com/yangjiaoshou/p/11322095.html
Copyright © 2011-2022 走看看