异常处理、UDP通信、socketserver模块
1、UDP通信基本使用
1、socket套接字的导入
import socket
server = socket.socket(type= socket.SOCK_DGRAM)
#type不写默认是TCP协议
服务端:
2、UDP没有半连接池的概念(listen),也无双向通道,无需accept,直接通信循环
3、接收数据有两个返回值:server.recvfrom(1024)
data,addr = server.recvfrom(1024)
print(data)#客户端的消息
print(addr)#客户端的地址
完整的服务端:
import socket
server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1',8080))
while True:
data ,addr = server.recvfrom(1024)
server.sendto(data.upper(),addr)
4、发数据:sendto
客户端:
无需建立连接的操作,直接进入通信循环。但是要给一个连接地址,用于发送
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
server_address = ('127.0.0.1'.8080)
while True:
client.sendto(b'hello',server_address)
data,addr = client.recvfrom(1024)
总结UDP和TCP的区别:
UDP相当于发短信;TCP相当于打电话
2、UDP与TCP的4大区别
-
UDP客户端允许发空:udp有一个报头
-
udp协议不会粘包:
不会粘包
#客户端代码 import socket client = socket.socket(type=socket.SOCK_DGRAM) server_address = ('127.0.0.1',8080) while True: client.sendto(b'hello',server_address) client.sendto(b'hello',server_address) client.sendto(b'hello',server_address)
#服务端代码 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 ,addr2 = server.recvfrom(1024) print(data) data ,addr3 = server.recvfrom(1024) print(data)
-
服务端断开的情况下,客户端不会报错:
会一直停留在客户端的”输入“那一行。但是如果继续输入,则会报错
ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
3、udp支持并发:看上去是同时运行的。
#服务端
import socket
server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1',8080))
while True:
data ,addr = server.recvfrom(1024)#在这里接受任何向这个地址发送消息的客户端。
server.sendto(data.upper(),addr)
4、实现一个简易版本的QQ
客户端代码
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
server_address = (('127.0.0.1',8080))
while True:
msg = input('>>>').encode('utf-8')
msg = '来自客户端1的信息:%s'%msg
client.sendto(msg.encode('utf-8'),server_address)
data,addr = client.recvfrom(1024)
print(data.decode('utf-8'))
服务端代码
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.decode('utf-8'))
msg = input('>>>')
server.sendto(msg.encode('utf-8'),addr)
5、socketserver模块
5.1 让TCP支持并发
#客户端代码
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
client.send(b'hello')
data = client.recv(1024)
print(data.decode('utf-8'))
#服务端代码
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
# print('来啦 老弟')
while True:
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() # 启动该服务对象
5.2socketserver同样支持UDP
#服务端代码
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
# print('来啦 老弟')
while True:
data,sock = self.request
print(self.client_address) # 客户端地址
print(data.decode('utf-8'))
sock.sendto(data.upper(),self.client_address)
if __name__ == '__main__':
"""只要有客户端连接 会自动交给自定义类中的handle方法去处理"""
server = socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyServer) # 创建一个基于TCP的对象
server.serve_forever() # 启动该服务对象
#客户端代码
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
client.send(b'hello')
data = client.recv(1024)
print(data.decode('utf-8'))
6、异常处理
当try中存在多个错误的时候,遇到第一个错误立即停止下面的代码,直接进“except”中弹出信息
try:
name#第一个错
l = [1,2,3]
l[111]#第二个错
d = {'name':'jason'}
d['password']#第三个错
except NameError:
print('NameError')
except IndexError:
print('indexerror')
except KeyError:
print('keyerror')
#运行程序的结果是NameError
Exception万能异常.以及else和finally
try:
# name
l = [1,2,3]
l[111]
# d = {'name':'jason'}
# d['password']
except Exception: # 万能异常 所有的异常类型都被捕获
print('老子天下无敌')
else:
print('被检测的代码没有任何的异常发生 才会走else')
finally:
print('无论被检测的代码有没有异常发生 都会在代码运行完毕之后执行我')
万能异常BaseException
try:
# name
l = [1,2,3]
l[111]
d = {'name':'jason'}
d['password']
# Exception
except BaseException: # 万能异常 所有的异常类型都被捕获
print('老子天下无敌')
BaseException是所有异常的祖宗。父类。
#点开源码
Exception(BaseException)
主动抛异常raise
if 'egon' == 'DSB':
pass
else:
raise TypeError('尽说大实话')# 关键字raise就是主动抛出异常
#命令行飘红(以下代码飘红)
Traceback (most recent call last):
File "C:/untitled6/32.py", line 4, in <module>
raise TypeError('尽说大实话')
TypeError: 尽说大实话
断言assert(判断)
l = ['a','b']
assert len(l) < 0
#与raise一样,运行结果飘红
自定义异常
class MyError(BaseException):
def __init__(self,msg):
super().__init__()
self.msg=msg
def __str__(self):
return '<dfsdf%ssdfsdaf>' %self.msg
raise MyError('我自己定义的异常') # 主动抛出异常其实就是将异常类的对象打印出来,会走__str__方法