-
tcp协议多人多次通信
-
bind:绑定一个ip和端口(元组)
-
listen:监听 代表socket服务已经起来了
-
accept:等待别人来连接
-
send:直接通过连接发送信息
-
recv::接收消息
-
connect:客户端tcp协议的方法
-
close:关闭 服务连接
-
socket()不写默认tcp协议
-
-
Dudp协议多人通信
-
bind:绑定一个ip和端口(元组)
-
sendto:需要写对方地址
-
recvfrom:接收消息和地址
-
socket(type = socket.SOCK_DGRAM) udp协议
-
close:关闭 服务连接
-
-
阻塞:
-
accept阻塞,当由客户端来和我建立连接
-
recv 直到收到对方发来的消息后
-
recvfrom 直到收到对方发来的消息后
-
connect 阻塞,直到server端与我建立连接后,
-
-
粘包:
-
两条或更多条分开发送的信息粘在一起了
-
发生在发送端:发送时间间隔店,数据小,由于优化机制,就合并一起发送了
-
发生在接收端:接收端接收不及时,所以数据在接收端的缓存端粘在一起了
-
粘包发生的本质:tcp协议的传输时流失传输,数据是没有边界的
-
解决粘包:自定义协议
-
先发送四字节的数据长度 先接收4字节长度的
-
按照数据长度发送数据 在按照长度接收
-
-
-
struck模块
-
pack pack('i',s)
-
unpack unpack('i',s)
-
二、今日内容
1、验证客户端的合法性
-
加密 hmac 和 hashlip模块
# 生成一个随机字符串
import os
ret = os.urandom(16)
print(ret)
import hashlib
sha = hashlib.sha1(密钥)
sha.update(随机字符串)
结果 = sha.hexdigest()
import os
import hmac # 替代hashlib模块的
h = hmac.new(b'alex_sb',os.urandom(32))
ret = h.digest()
print(ret) -
在网络传输时,客户端和服务端要做信息验证时,可以使用加密来核对信息和交互
import os
import socket
import hashlib
secret_key = b'alex_sb'
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
conn,addr = sk.accept()
# 创建一个随机的字符串
rand = os.urandom(32)
# 发送随机字符串
conn.send(rand)
# 根据发送的字符串 + secrete key 进行摘要
sha = hashlib.sha1(secret_key)
sha.update(rand)
res = sha.hexdigest()
# 等待接收客户端的摘要结果
res_client = conn.recv(1024).decode('utf-8')
# 做比对
if res_client == res:
print('是合法的客户端')
# 如果一致,就显示是合法的客户端
# 并可以继续操作
conn.send(b'hello')
else:
conn.close()
# 如果不一致,应立即关闭连接
2、并发的tcp协议server端 ——socketserver
-
socketserver基于socket完成的
-
作用:处理并发的客户端请求
#server端
import socketserver
import time
class Myserver(socketserver.BaseRequestHandler):
def handle(self):
conn = self.request
while True:
try:
ret = conn.recv(1024).decode('utf-8')
conn.send(ret.upper().encode('utf-8'))
time.sleep(0.5)
except ConnectionResetError:
break
server = socketserver.ThreadingTCPServer(('127.0.0.1',9001),Myserver)
server.serve_forever()
#client端
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
while True:
sk.send(b'hello')
msg = sk.recv(1024).decode('utf-8')
print(msg)
3、tcp协议的自定义协议解决粘包问题
-
-
两条连续发送的数据一定要避免粘包问题
-
先发送数据的长度 再发送数据
-
发送的数据相关的内容组成json:先发json的长度,再发json,json中存了接下来要发送的数据长度,再发数据
-
#server端
import json
import struct
import socket
# 接收
sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
conn,_ =sk.accept()
msg_len = conn.recv(4)
dic_len = struct.unpack('i',msg_len)[0]
msg = conn.recv(dic_len).decode('utf-8')
msg = json.loads(msg)
with open(msg['filename'],'wb') as f:
while msg['filesize'] > 0:
content = conn.recv(1024)
msg['filesize'] -= len(content)
f.write(content)
conn.close()
sk.close()
#client
import os
import json
import struct
import socket
# 发送
sk = socket.socket()
# sk.connect(('192.168.14.109',9012))
sk.connect(('127.0.0.1',9001))
# 文件名文件大小
abs_path = r'D:python22期day28 课上视频3.网络基础概念.mp4'
filename = os.path.basename(abs_path)
filesize = os.path.getsize(abs_path)
dic = {'filename':filename,'filesize':filesize}
str_dic = json.dumps(dic)
b_dic = str_dic.encode('utf-8')
mlen = struct.pack('i',len(b_dic))
sk.send(mlen) # 4个字节 表示字典转成字节之后的长度
sk.send(b_dic) # 具体的字典数据
with open(abs_path,mode = 'rb') as f:
while filesize>0:
content = f.read(1024)
filesize -= len(content)
sk.send(content)
sk.close()