zoukankan      html  css  js  c++  java
  • 异常处理 UDP通信

    异常处理


    什么是异常?

    ​ 程序在运行过程中出现了不可预知的错误

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

    ​ 造成的影响就是整个程序无法运行

    异常的结构

    ​ 1.异常的类型

    ​ 2.异常的信息

    ​ 3.异常的位置

    异常的种类

    ​ 分为两大类
    ​ 1.语法错误
    ​ 是你程序立刻就能解决的,这种错误是不能被容忍的
    ​ 语法上的错误 发现之后应该立刻解决

    ​ 2.逻辑错误
    ​ 这种错是可以被容忍的 因为一眼看不出来
    ​ 针对逻辑上的错误 可以采用异常处理机制进行捕获

    常见的错误类型

    常见的出错类型 含义
    SyntaxError 语法错误
    NameError 名字错误
    KeyError 键不存在(推荐在字典用get取值,这样不会报这个错,get里面放两个参数,左边一个是要找的key,如果key不存在,返回右边的值)
    ValueError 值错误
    IndexError 索引错误

    except 可以叠加写

    错误发生之后 会立刻停止代码的运行

    执行 except语句 比对错误类型

    except NameError:
    		print('捕获了NameError')
    except KeyError:
    		print('捕获了KeyError')
    

    比如首先出现了NameError 就不会继续查看是否有KeyError

    万能异常

    所有的错误类型都能捕获

    except Exception

    except BaseException

    这两个都是万能异常处理的方法

    Exception 继承了BaseException

    except 之后还可以加一个else :

    最后也可以加一个finally

    (try.. except.. else.. finally..)

    except Exception:
    		print('万能异常捕获')
    else:
    		print('没报错,才会走else')
    finally:
    		print('无论如何,这句都会打印')
    

    # finally的用处:比如在代码结束之后结束读写啥的

    主动报异常

    if 'bitten' == 'DSB'
    		pass
    else:
    		raise TypeError('净说实话')
    

    # 关键字raise就是主动抛出异常

    断言assert

    # 断言不成立直接报错

    l = [1,2,3]
    assert len(l) < 0  # assert 断言,预言,猜某个数据的状态,猜对了不影响代码执行,猜错了直接报错
    

    自定义异常(继承异常类)

    报错类型,其实对应的就是一个个类(可以自定义拼接异常的格式)

    class MyError(BaseException):
        def __init__(self, msg):
            super().__init__()
            self.msg = msg
        
        def __str__(self):
            return f'----<{self.msg}>----'
    
    raise MyError('自定义的异常')
    # Traceback (most recent call last):
    #   File "E:/PyCharm 2019.1.3/ProjectFile/day010/day029/test.py", line 15, in <module>
    #     raise MyError('自定义的异常')
    # __main__.MyError: ----<自定义的异常>----
    

    UDP通信


    UDP协议又叫用户数据报协议

    它没有双向通道,类似于发短信(只管发,不管对方有没有收到,不需要对方立即回应)

    UDP的程序可以先启动客户端再启动服务端(客户端发数据给服务端之前都没问题)

    UDP类似于发短信

    TCP类似于打电话,你一句我一句的

    普通使用


    服务端

    import socket
    
    server = socket.socket(type=socket.SOCK_DGRAM)  # type=socket.SOCK_DGRAM 指定成 UDP 协议  type=socket.SOCK_STREAM TCP协议(默认就是,不用指定)
    server.bind(('127.0.0.1', 8080))
    
    # UDP 不需要设置半连接池(server.listen(5)),也没有半连接池的概念
    # UDP 没有双向通道,所以也不需要建立连接(conn, addr = server.accept())
    
    # 直接就是通信循环
    
    while True:  # 这里只需要直接通信(交互)即可
        data, addr = server.recvfrom(1024)
        print("数据:", data.decode('utf-8'))  # 客户端发来的消息
        print("地址:", addr)  # 客户端的地址
    
        re_msg = input("Please input your response msg:").strip()  # 会阻塞在这里,这里过了,才能发出信息,看到下一条信息
        server.sendto(re_msg.encode('utf-8'), addr)  # 向客户端发送消息
    
    
    # 数据: hi
    # 地址: ('127.0.0.1', 64821)
    # Please input your response msg:o  hi
    # 数据: hihihi
    # 地址: ('127.0.0.1', 64823)
    # Please input your response msg:xxixixi
    # 数据: aha e
    # 地址: ('127.0.0.1', 64828)
    # Please input your response msg:emmm?
    # 数据:
    # 地址: ('127.0.0.1', 64828)
    # Please input your response msg:adsa
    

    客户端

    import socket
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    
    # UDP 不需要建立连接(client.connect(('127.0.0.1', 8080)))
    
    server_addr = ('127.0.0.1', 8080)  # UDP sendto发消息时需要一个服务器的地址及端口号
    
    while True:
        msg = input("Please input your msg:").strip()
        client.sendto(msg.encode('utf-8'), server_addr)  # 向服务器发送数据,要附带服务器端地址及端口(基于网络传输的数据都必须是二进制的)
        data, msg_from_server_addr = client.recvfrom(1024)  # 收到消息,且得到地址
    
        print("服务端发来的数据:", data.decode('utf-8'))
        print("服务器端的ip及端口", msg_from_server_addr)
    
    # 窗口1
    # Please input your msg:hi
    # 服务端发来的数据: o  hi
    # 服务器端的ip及端口 ('127.0.0.1', 8080)
    # Please input your msg:
    
    # 窗口2
    # Please input your msg:hihihi
    # 服务端发来的数据: xxixixi
    # 服务器端的ip及端口 ('127.0.0.1', 8080)
    # Please input your msg:
    
    # 窗口3
    # Please input your msg:aha e
    #
    # 服务端发来的数据: emmm?
    # 服务器端的ip及端口 ('127.0.0.1', 8080)
    # Please input your msg:服务端发来的数据: adsa
    # 服务器端的ip及端口 ('127.0.0.1', 8080)
    # Please input your msg:
    

    TCP与UDP之间的区别


    1.UDP 允许发空数据,不会有影响

    2.UDP 直接启动客户端未启动服务端不会报错

    3.UDP 不会有粘包问题(自带报头)

    4.UDP 支持并发

    服务端

    import socket
    
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1',8080))
    
    # while True:
    data, addr = server.recvfrom(1024)
    print(data)
    data, addr1 = server.recvfrom(1024)
    print(data)
    data, addr2 = server.recvfrom(1024)
    print(data)
    

    客户端

    import socket
    
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    
    while True:
    
        msg = input(">>>:")
        # -------------------------------------------
        # 1.UDP 允许发空数据,不会有影响
        # -------------------------------------------
        # UDP自带报头,就算数据为空,另一端也能处理
        client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))  # 第二参数,目标服务器地址
    
        # -------------------------------------------
        # 2.UDP 直接启动客户端未启动服务端不会报错
        #   发数据找不到服务端也还是会报错
        # -------------------------------------------
        # 下面两行代码直接注释掉,服务端没启动,都不会报错,只管给服务器发(收没收到不管)
        # data, server_addr = client.recvfrom(1024)
        # print(data)
    
        # -------------------------------------------
        # 3.UDP 不会有粘包问题(自带报头)
        # -------------------------------------------
        # client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
        # client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
        # client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
        #
        # server.sendto(data.upper(), addr)
        # server.sendto(data.upper(), addr)
        # server.sendto(data.upper(), addr)
    
        # -------------------------------------------
        # 4.UDP 支持并发
        #   TCP是保持连接,而UDP不需要保持连接
        #       与一个客户端断开连接才会和下一个客户端建立连接
        # -------------------------------------------
    

    UDP实现简易版QQ


    服务器端

    import socket
    
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1', 8080))
    
    while True:
        data, client_addr = server.recvfrom(1024)
        print(data.decode('utf-8'))
    
        msg = input(">>>:").strip()
        server.sendto(msg.encode('utf-8'), client_addr)
    
    # 来自star3的消息:helo
    # >>>:hi
    # 来自star2的消息:aha
    # >>>:haa
    # 来自star的消息:hello world
    # >>>:ha
    # 来自star2的消息:jason nnn
    # >>>:jj
    

    客户端1,2,3共用同一份代码

    import socket
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    
    username = 'star'
    server_address = ('127.0.0.1', 8080)  # 指定一个发消息的目标服务器
    while True:
        msg = input(">>>:").strip()
    
        msg = f'来自{username}的消息:{msg}'  # 是哪个用户名发出的数据不应该由这里传过去,用户可以随便改,实际意义不大
        '''
        user_dict = {
            "username1": (ip1 + port1),
            "username2": (ip2 + port2),
            "username3": (ip3 + port3),
        }
        # 可以在每个端都存这样一个对照表,根据ip与port就可以知道用户名了
        '''
    
        client.sendto(msg.encode('utf-8'), server_address)
    
        data, server_addr = client.recvfrom(1024)  # server_addr 收到消息的服务端地址
    
        print(data.decode('utf-8'))
    
    # 各个窗口的控制台输入与输出
    # >>>:helo
    # hi
    # >>>:
    
    # >>>:aha
    # haa
    # >>>:jason nnn
    # jj
    
    # >>>:
    # >>>:hello world
    # ha
    # >>>:
    

    socketserver模块科普


    是给服务端用的( 客户端还是用socket模块 ),可以保持连接

    TCP模拟UDP实现并发

    服务器端

    import socketserver  # 文件名不要和模块冲突了,不然都不知道导哪个了
    
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            # 与客户端进行通信
            # print("来啦 老弟")
            while True:  # 需要保持通信(后续 client.send() 可没有附带服务器地址, connect 被关闭了)
                data = self.request.recv(1024)
                print(self.client_address)  # 客户端地址
                print(data.decode('utf-8'))
                self.request.send(data.upper())
    
    if __name__ == '__main__':
        '''只要有客户端连接,会自动交给自定义类中的handle方法去处理'''
        server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyServer)  # 创建一个基于TCP的对象
        server.serve_forever()  # 启动该服务对象
    
    # ('127.0.0.1', 14327)
    # dAddA
    # ('127.0.0.1', 14326)
    # ADD
    # ('127.0.0.1', 14325)
    # ADsafga
    

    客户端

    # TCP 实现UDP
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1', 8080))
    
    while True:
        res = input(">>>:")
        client.send(res.encode('utf-8'))
    
        data = client.recv(1024)
        print(data.decode('utf-8'))
    
    
    # 窗口1 控制台数据(输入与输出)
    # >>>:dAddA
    # DADDA
    # >>>:
    
    # 窗口2 控制台数据(输入与输出)
    # >>>:ADD
    # ADD
    # >>>:
    
    # 窗口1 控制台数据(输入与输出)
    # >>>:ADsafga
    # ADSAFGA
    # >>>:
    

    socketserver之UDP

    服务器端

    import socketserver  # 文件名不要和模块冲突了,不然都不知道导哪个了
    
    
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            # 与客户端进行通信
            # while True:  # UDP 不需要通信循环,每次 sendto 都有服务器的地址
            data, sock = self.request
            print(self.client_address)  # 客户端地址
            print(data.decode('utf-8'))
            sock.sendto(data.lower(), self.client_address)
    
    
    if __name__ == '__main__':
        '''只要有客户端连接,会自动交给自定义类中的handle方法去处理'''
        server = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyServer)  # 创建一个基于UDP的对象
        server.serve_forever()  # 启动该服务对象
    
    # 控制台打印的数据
    # ('127.0.0.1', 52524)
    # CLient2
    # ('127.0.0.1', 52529)
    # clet1
    # ('127.0.0.1', 52529)
    # CLienT1
    # ('127.0.0.1', 54485)
    # CLiEnt3
    

    客户端

    import socket
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    
    server_addr = ('127.0.0.1', 8080)
    
    while True:
        res = input(">>>:").strip()
        client.sendto(res.encode('utf-8'), server_addr)
    
        data, response_server_addr = client.recvfrom(1024)
        print(data.decode('utf-8'), response_server_addr)
    
    # 窗口1 控制台数据(输入与输出)
    # >>>:clIeNt1
    # clet1 ('127.0.0.1', 8080)
    # >>>:CLienT1
    # client1 ('127.0.0.1', 8080)
    # >>>:
    
    # 窗口2 控制台数据(输入与输出)
    # >>>:CLient2
    # client2 ('127.0.0.1', 8080)
    # >>>:
    
    # 窗口1 控制台数据(输入与输出)
    # >>>:CLiEnt3
    # client3 ('127.0.0.1', 8080)
    # >>>:
    

    为什么UDP不用写通信循环

    ​ handle 是处理一次连接请求的,handle结束连接就断开了

    ​ UDP是不需要保持(双向)连接的,所以每次sendto 都是单个请求(都附带服务器端地址及端口),不能写通信循环(不然就拿着一个sendto 过来的数据循环打印了)

    ​ 而TCP是基于双向通道通信的,handle结束后连接就断开了(再client.send() 这个连接状态就已经不存在了),所以TCP这边的服务端要写通信循环保持连接来多次通信

  • 相关阅读:
    SqlLiteHelper:基于C#的SqlLite数据库访问基类
    SQL注入专题整理帖
    SQLite数据库查询优化
    php mysql与mysqli 区别
    PHPCMS V9模板制作常用变量表
    实用正则手机和邮箱
    windows2003+iis6.0+php(fastcgi)5.3+wincache+memcached
    ajax 写法
    php防注入,表单提交值转义
    IE6下的两个兼容问题调试
  • 原文地址:https://www.cnblogs.com/PowerTips/p/11322071.html
Copyright © 2011-2022 走看看