一、异常处理
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 |