一、异常处理
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
3)异常处理的单分支结构
try: l=[1,2,3] l[100] print('====>') except IndexError: print('=====>NameError') print('其他代码')
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('其他代码')
5)万能异常:Exception,可以匹配所有种类的异常,最好不要直接万能匹配异常
try: # age l=[1,2,3] # l[100] d={'x':1} d['y'] print('====>') except Exception as e: print(e) print('其他代码')
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('其他代码')
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的代码只有在被检测的代码块没有异常发生的情况下才会执行')
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('其他代码')
9)主动触发异常raise 异常类型(’异常的内容‘)
print('===>1') raise TypeError('类型错误') print('===>2') # 应用于程序中自定义某种法则,一旦不遵循则会像抛出语法异常一样,终止程序的运行
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')
11)自定义异常
class MyError(BaseException): def __init__(self,msg): super().__init__() self.msg=msg def __str__(self): return '<%s>' %self.msg raise MyError('我自己定义的异常')
二、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()
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)
三、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