内容回顾:
粘包现象:
TCP协议:
是一种流式传输,传输的是字节流,但是数据与数据之间是没有边界的,
流式传输:
不限定长度
传输方式可靠
传输速度慢
通信的过程中,连接conn会一直占用通讯资源
DUP协议:
面向数据包的传输
什么是数据包?
每次信息的发送,都是将: 自己的ip_port+对方的ip_port+message 以文件包的形式发送给对方
不能传输过长的数据
传输过程不可靠,数据会丢失
传输速度快
由于不需要建立连接,因此谁发过来的信息都能接收
内容大纲:
TCP协议中,server堵塞的取消
验证客户端的合法性
并发的socketserver
实现统一时刻server端可以和多个client客户端建立连接
TCP协议中,server堵塞的取消
import socket sk = socket.socket() sk.bind(('127.0.0.1',8989)) sk.setblocking(False)#取消堵塞 sk.listen() while True: try: conn,addr = sk.accept() except BlockingIOError: conn.recv()
#为什么要验证客户端的合法性?
一些恶意的用户,如果知道server的ip地址,会采用扫端口的方法,端口0-65535,试出正确的端口,
从而与server端取得联系,接收server发来的信息,或者给server端发送病毒,攻击server端。
所以server在与client取得连接的时候需要验证客户端的合法性
验证客户端的过程?
server端 ---------------------随机的字符串---------------------->client端
根据相同的算法 根据特殊的算法,进行处理得到一个结果
的到一个结果与client端发送过的进行比较
如果验证通过,那么对方就是合法的客户端
server端:
import socket import os import hmac secret_key = b'alex' sk = socket.socket() sk.bind(('127.0.0.1',8989)) sk.listen() conn,addr = sk.accept() def auth(conn): msg = os.urandom(32)#本身就是bytes类型的#生成一个随机的字符串 conn.send(msg)#发送改字符串到客户端 result = hmac.new(secret_key,msg)#secret_key加盐,处理这个字符串,得到一个结果 client_digest = conn.recv(1024)#接收client发过来的结果 if result.hexdigest() == client_digest.decode('utf-8'):#对比验证是否继续通讯 print('合法的链接') return True else:#不通过close print('不合法的链接') return False if auth(conn): print(conn.recv(1024)) conn.close() else:conn.close() sk.close()
#client端:
import socket import hmac secret_key = b'alex' sk = socket.socket() sk.connect(('127.0.0.1',8989)) def auth(sk): msg = sk.recv(32) result = hmac.new(secret_key,msg)#<hmac.HMAC object at 0x0000003C1CFE7F98> print(result) res = result.hexdigest()#3f7f94cece407db2689b13c634467357 print(res) sk.send(res.encode('utf-8')) auth(sk) sk.send(b'hello') sk.close()
#socketserver这个模块超级有用,一定得记下来
socketserver是socket更上一级的模块,涵盖了socket的所有功能
socketserver建立在面向对象的编程
server基本框架:
import socketserver #不需要再导入socket class Myserver(socketserver.BaseRequestHandler): def handle(self): conn = self.request#对于每个来访问的客户都是从这里建立连接 pass#具体的收发内容 server = socketserver.ThreadingTCPServer(('127.0.0.1',9000),Myserver) server.serve_forever()#建立多用户端的server
client端代码:
import socketserver #不需要再导入socket class Myserver(socketserver.BaseRequestHandler): def handle(self):#重写源码里面你的handle方法 conn = self.request while True: conn.send(b'hello') print(conn.recv(1024)) server = socketserver.ThreadingTCPServer(('127.0.0.1',9000),Myserver) server.serve_forever()#建立多用户端的server
client-taibai端:
import socket sk = socket.socket() sk.connect(('127.0.0.1',9000)) while True: print(sk.recv(1024)) sk.send(b'taibai')
client-alex端:
import socket sk = socket.socket() sk.connect(('127.0.0.1',9000)) while True: print(sk.recv(1024)) sk.send(b'alex')