• Python之异常处理和socket套接字连接7


    一、异常处理

    1)异常处理的使用意义

    1 什么是异常处理
        异常是程序发生错误的信号,即程序一旦出错就会立刻产生一个异常,如果该异常没有被处理
        那么异常就抛出来,程序的运行也随之终止
    
        异常分为三部分:
            异常的类型
            异常的内容、提示信息
            异常的追踪/定位信息信息
    
        捕捉/检测异常,一旦发生异常就立刻执行相应的处理逻辑,而不是任由异常抛出来终止程序
    2 为何要进行异常处理
        增强程序的健壮性
    
    3 如何进行异常处理
        try...except...

    2)逻辑错误导致的异常

    # int('xxxxxxx') #ValueError
    
    # age #NameError
    
    # for i in 10: #TypeError:
    #     pass
    
    # l=[]
    # l[1111111] #IndexError
    
    # d={'x':1}
    # d['y'] #KeyError
    
    # 1 / 0 #ZeroDivisionError
    View Code

    3)异常处理的单分支结构

    try:
        l=[1,2,3]
        l[100]
        print('====>')
    except IndexError:
        print('=====>NameError')
    print('其他代码')
    View Code

    4)异常的多分支结构

    try:
        age
        l=[1,2,3]
        # l[100]
        d={'x':1}
        # d['y']
        print('====>')
    except NameError as e:
        print('NameError: %s' %e)
    except IndexError as e:
        print('IndexError: %s' %e)
    except KeyError as e:
        print('KeyError: %s' %e)
    
    print('其他代码')
    View Code

    5)万能异常:Exception,可以匹配所有种类的异常,最好不要直接万能匹配异常

    try:
        # age
        l=[1,2,3]
        # l[100]
        d={'x':1}
        d['y']
        print('====>')
    except Exception as e:
        print(e)
    
    
    print('其他代码')
    View Code

     6)多分支+Exception,注意Exception一定要放到except 其他异常的的后面

    try:
        d={'x':1}
        d['y']
        print('====>')
    except IndexError as e:
        print('IndexError: %s' %e)
    except KeyError as e:
        print('KeyError:%s' %e)
    except Exception as e:
        print(e)
    
    print('其他代码')
    View Code

    7)try...else,else会在被检测的代码块没有异常发生的情况下执行, else一定要与except连用,并且一定要放到多个except后面

    try:
        l=[1,2,3]
        print('====>')
    except IndexError as e:
        print('IndexError: %s' %e)
    except KeyError as e:
        print('KeyError:%s' %e)
    except Exception as e:
        print(e)
    else:
        print('else的代码只有在被检测的代码块没有异常发生的情况下才会执行')
    View Code

    8)try...finally,finnaly的代码会什么时候运行? finally应放到最后面,常应用于回收资源使用

    try:
        f=open('a.txt','w')
        d={'x':1}
        print(d['y'])
    except KeyError as e:
        print('KeyError:%s' %e)
    except Exception as e:
        print(e)
    else:
        print('else的代码只有在被检测的代码块没有异常发生的情况下才会执行')
    finally:
        print('finally的代码,无论被检测的代码有无异常,都会执行,通常在finally内做一些回收资源的事情')
        f.close()
    
    print('其他代码')
    View Code

    9)主动触发异常raise 异常类型(’异常的内容‘)

    print('===>1')
    raise TypeError('类型错误')
    print('===>2')
    # 应用于程序中自定义某种法则,一旦不遵循则会像抛出语法异常一样,终止程序的运行
    View Code

     10)断言,和代替raise触发的异常

    info=[1,2,3,4,5,6]
    
    # if len(info) != 7:
    #     raise ValueError('值的个数 < 7')
    assert len(info) == 7 # 我断定len(info) == 7,如果我断言失败,程序则抛出异常
    
    print('阶段2--->1')
    View Code

     11)自定义异常

    class MyError(BaseException):
        def __init__(self,msg):
            super().__init__()
            self.msg=msg
        def __str__(self):
            return '<%s>' %self.msg
    
    raise MyError('我自己定义的异常')
    View Code

     二、socker套接字网络编程,tcp连接方式

    1)套接字工作流程

    先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束

     2)实例化出简单的服务端和客户端程序

    import socket
    
    #1、买手机
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式协议指的就是tcp协议
    # print(phone)
    
    #2、插手机卡
    phone.bind(('127.0.0.1',8080)) #端口范围0-65535
    
    #3、开机
    phone.listen(5) #限制的是请求数,而非链接数
    
    #4、等待电话连接
    print('服务的启动......')
    conn,client_addr=phone.accept() #(tcp的连接对象,客户端的ip和端口)
    print(conn)
    print(client_addr)
    
    #5、收消息
    data=conn.recv(1024) #最大接收1024bytes
    print('客户端数据:%s' %data)
    #6、发消息
    conn.send(data.upper())
    
    #7、挂电话
    conn.close()
    
    #9、关机
    phone.close()
    服务端
    import socket
    
    #1、买手机
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式协议指的就是tcp协议
    
    #2、打电话,建电话连接
    phone.connect(('127.0.0.1',8080)) #ip和端口都是服务端的
    
    #3、发消息
    phone.send('hello world'.encode('utf-8'))
    
    #4、收消息
    data=phone.recv(1024)
    print(data)
    
    #5、挂电话
    phone.close()
    客户端

    3)加上通信循环

    import socket
    
    #1、买手机
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式协议指的就是tcp协议
    # print(phone)
    
    #2、插手机卡
    phone.bind(('127.0.0.1',8080)) #端口范围0-65535
    
    #3、开机
    phone.listen(5) #限制的是请求数,而非链接数
    
    #4、等待电话连接
    print('服务的启动......')
    conn,client_addr=phone.accept() #(tcp的连接对象,客户端的ip和端口)
    print(conn)
    print(client_addr)
    
    while True: # 通信循环
        try: #针对的是windows系统
            #5、收消息
            data=conn.recv(1024) #最大接收1024bytes
            if not data:break #针对的linux系统
            print('客户端数据:%s' %data)
            #6、发消息
            conn.send(data.upper())
        except ConnectionResetError:
            break
    
    #7、挂电话
    conn.close()
    
    #9、关机
    phone.close()
    服务端
    import socket
    
    #1、买手机
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式协议指的就是tcp协议
    
    #2、打电话,建电话连接
    phone.connect(('127.0.0.1',8080)) #ip和端口都是服务端的
    
    while True:
        msg=input('>>>: ').strip()
        #3、发消息
        phone.send(msg.encode('utf-8'))
    
        #4、收消息
        data=phone.recv(1024)
        print(data.decode('utf-8'))
    
    #5、挂电话
    phone.close()
    客户端

    4)加上连接循环,可等待多个连接进来

    import socket
    
    #1、买手机
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式协议指的就是tcp协议
    # print(phone)
    # phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
    
    #2、插手机卡
    phone.bind(('127.0.0.1',8081)) #端口范围0-65535
    
    #3、开机
    phone.listen(5) #限制的是请求数,而非链接数
    
    #4、等待电话连接
    print('服务的启动......')
    
    while True: # 连接循环
        conn,client_addr=phone.accept() #(tcp的连接对象,客户端的ip和端口)
        # print(conn)
        print(client_addr)
    
        # 通信循环
        while True:
            try: #针对的是windows系统
                #5、收消息
                data=conn.recv(1024) #最大接收1024bytes
                if not data:break #针对的linux系统
                print('客户端数据:%s' %data)
                #6、发消息
                conn.send(data.upper())
            except ConnectionResetError:
                break
    
        #7、挂电话
        conn.close()
    
    #9、关机
    phone.close()
    服务端
    import socket
    
    #1、买手机
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式协议指的就是tcp协议
    
    #2、打电话,建电话连接
    phone.connect(('127.0.0.1',8081)) #ip和端口都是服务端的
    
    while True:
        msg=input('>>>: ').strip() #msg=''
        if not msg:continue
        #3、发消息
        phone.send(msg.encode('utf-8'))
        print('has send====>')
    
        #4、收消息
        data=phone.recv(1024)
        print('has recv====>')
        print(data.decode('utf-8'))
    
    #5、挂电话
    phone.close()
    客户端

    5)模拟ssh远程执行命令

    from socket import *
    import subprocess
    
    phone=socket(AF_INET,SOCK_STREAM)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)
    
    print('服务的启动......')
    # 连接循环
    while True:
        conn,client_addr=phone.accept()
        print(client_addr)
    
        # 通信循环
        while True:
            try:
                cmd=conn.recv(1024)
                if not cmd:break
    
                obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE
                                 )
    
                stdout=obj.stdout.read()
                stderr=obj.stderr.read()
    
                # conn.send(stdout+stderr)
                print(len(stdout)+len(stderr))
                conn.send(stdout)
                conn.send(stderr)
            except ConnectionResetError:
                break
        conn.close()
    
    phone.close()
    服务端
    from socket import *
    
    phone=socket(AF_INET,SOCK_STREAM)
    phone.connect(('127.0.0.1',8081))
    
    while True:
        cmd=input('>>>: ').strip()
        if not cmd:continue
        phone.send(cmd.encode('utf-8'))
    
        res=phone.recv(1024) #1024 * 8
        print(res.decode('gbk'))
    
    
    phone.close()
    客户端

    发现了粘包问题

     6)解决粘包问题

    from socket import *
    import subprocess
    import struct
    
    phone=socket(AF_INET,SOCK_STREAM)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)
    
    print('服务的启动......')
    # 连接循环
    while True:
        conn,client_addr=phone.accept()
        print(client_addr)
        # 通信循环
        while True:
            try:
                cmd=conn.recv(1024)
                if not cmd:break
                obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE
                                 )
                stdout=obj.stdout.read()
                stderr=obj.stderr.read()
                # 1、先发送固定长度的报头
                #目前报头里只包含数据的大小
                total_size=len(stdout) + len(stderr)
                conn.send(struct.pack('i',total_size))
                # 2、发送真实的数据
                conn.send(stdout)
                conn.send(stderr)
            except ConnectionResetError:
                break
        conn.close()
    phone.close()
    服务端
    from socket import *
    import struct
    
    phone=socket(AF_INET,SOCK_STREAM)
    phone.connect(('127.0.0.1',8081))
    while True:
        cmd=input('>>>: ').strip()
        if not cmd:continue
        phone.send(cmd.encode('utf-8'))
        #1、先收报头,从报头里取出对真实数据的描述信息
        header=phone.recv(4)
        total_size=struct.unpack('i',header)[0]
        #2、循环接收真实的数据,直到收干净为止
        recv_size=0
        res=b''
        while recv_size < total_size:
            recv_data=phone.recv(1024)
            res+=recv_data
            recv_size+=len(recv_data)
        print(res.decode('gbk'))
    phone.close()
    客户端

     7)解决粘包报头数据过大问题,先转json,再转报头

    from socket import *
    import subprocess
    import struct
    import json
    
    phone=socket(AF_INET,SOCK_STREAM)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)
    
    print('服务的启动......')
    # 连接循环
    while True:
        conn,client_addr=phone.accept()
        print(client_addr)
    
        # 通信循环
        while True:
            try:
                cmd=conn.recv(1024)
                if not cmd:break
                obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE
                                 )
    
                stdout=obj.stdout.read()
                stderr=obj.stderr.read()
    
                #制作报头
                header_dic={
                    'filename':'a.txt',
                    'total_size':len(stdout) + len(stderr),
                    'md5':'xxxxxsadfasdf123234e123'
                }
                header_json = json.dumps(header_dic)
                header_bytes=header_json.encode('utf-8')
    
                #1、先发送报头的长度
                conn.send(struct.pack('i',len(header_bytes)))
    
                #2、再发送报头
                conn.send(header_bytes)
    
                #3、最后发送真实的数据
                conn.send(stdout)
                conn.send(stderr)
    
            except ConnectionResetError:
                break
        conn.close()
    
    phone.close()
    服务端
    from socket import *
    import struct
    import json
    
    phone=socket(AF_INET,SOCK_STREAM)
    phone.connect(('127.0.0.1',8081))
    
    while True:
        cmd=input('>>>: ').strip()
        if not cmd:continue
        phone.send(cmd.encode('utf-8'))
    
        #1、先收报头的长度
        obj=phone.recv(4)
        header_size=struct.unpack('i',obj)[0]
    
        #2、再接收报头
        header_bytes=phone.recv(header_size)
        header_json=header_bytes.decode('utf-8')
        header_dic=json.loads(header_json)
        print(header_dic)
    
        total_size=header_dic['total_size']
        #3、循环接收真实的数据,直到收干净为止
        recv_size=0
        res=b''
        while recv_size < total_size:
            recv_data=phone.recv(1024)
            res+=recv_data
            recv_size+=len(recv_data)
    
        print(res.decode('gbk'))
    
    phone.close()
    客户端

    8) socketserver模块实现并发的套接字通信

    基于tcp的并发线程通信

    import socketserver
    
    # 通信循环
    class MyTCPHandler(socketserver.BaseRequestHandler):
        def handle(self):
            while True:
                try:
                    data=self.request.recv(1024)
                    if not data:break
                    self.request.send(data.upper())
                except ConnectionResetError:
                    break
            self.request.close()
    if __name__ == '__main__':
        # 连接循环
        server=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyTCPHandler)
        server.serve_forever()
    服务端
    import socket
    
    client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    client.connect(('127.0.0.1',8080)) #ip和端口都是服务端的
    
    while True:
        msg=input('>>>: ').strip()
        client.send(msg.encode('utf-8'))
        data=client.recv(1024)
        print(data.decode('utf-8'))
    
    
    client.close()
    客户端

    基于udp的并发线程通信 

    import socketserver
    
    # 通信循环
    class MyUDPHandler(socketserver.BaseRequestHandler):
        def handle(self):
            # print(self.request)
            res=self.request[0]
            print('客户端发来的数据:',res)
    
            self.request[1].sendto(res.upper(),self.client_address)
    
    if __name__ == '__main__':
        #连接循环
        server=socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyUDPHandler)
        server.serve_forever()
    udpserver
    import socket
    import os
    
    client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    
    while True:
        msg='%s hello' %os.getpid()
        client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))
    
        res,server_addr=client.recvfrom(1024)
        print(res)
    udpclient

    三、socket套接字,基于UDP的连接方式

    1)udp的工作模式

    from socket import *
    import time
    
    server=socket(AF_INET,SOCK_DGRAM) # 数据报协议UDP
    #1、基于udp协议每发送的一条数据都自带边界,即udp协议没有粘包问题
    #2、基于udp协议的通信,一定是一发对应一收
    
    server.bind(('127.0.0.1',8080))
    
    while True:
        msg,client_addr=server.recvfrom(1024)   # 接收客户端的信息
        print(msg ,client_addr)
        time.sleep(3)
        server.sendto(msg.upper(),client_addr)      # 给客户端回消息
    服务端
    from socket import *
    
    client=socket(AF_INET,SOCK_DGRAM)
    
    while True:
        # msg=input('>>: ').strip()
        client.sendto('egon'.encode('utf-8'),('127.0.0.1',8080))    # 给服务端发送消息
    
        res,server_addr=client.recvfrom(1024)
        print(res)
    客户端

     2) udp的连接特点

    1、一发对应一收
    2、没有粘包问题
    3、只能接收数据量比较小的内容,如果接收的byte数量小于了发送的数量,会丢数据
    from socket import *
    
    server=socket(AF_INET,SOCK_DGRAM) # 数据报协议UDP
    #1、基于udp协议每发送的一条数据都自带边界,即udp协议没有粘包问题
    #2、基于udp协议的通信,一定是一发对应一收
    
    server.bind(('127.0.0.1',8080))
    
    msg1,client_addr=server.recvfrom(1)
    print(msg1)
    msg2,client_addr=server.recvfrom(1)
    print(msg2)
    msg3,client_addr=server.recvfrom(1)
    print(msg3)
    服务端
    from socket import *
    
    client=socket(AF_INET,SOCK_DGRAM)
    
    client.sendto('hello'.encode('utf-8'),('127.0.0.1',8080))
    client.sendto('world'.encode('utf-8'),('127.0.0.1',8080))
    client.sendto('egon'.encode('utf-8'),('127.0.0.1',8080))
    客户端

    原文链接:http://www.cnblogs.com/linhaifeng/articles/6129246.html

  • 相关阅读:
    剑指offer-整数中1出现的次数
    剑指offer-连续子数组的最大和
    剑指offer-最小的k个数
    剑指offer-数组中超过一半的数字
    剑指offer-二叉搜索树与双向链表
    剑指offer-复杂链表的复制
    剑指offer-二叉树中和为某一值的路径
    剑指offer-二叉搜索树的后序遍历
    Alpha 冲刺 (7/10)
    Alpha 冲刺 (6/10)
  • 原文地址:https://www.cnblogs.com/linu/p/9127914.html
Copyright © 2020-2023  润新知