python网络编程 day30 网络编程——hmac模块与hashlip、socketserver、粘包问题

一、内容回顾

  • 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协议的自定义协议解决粘包问题

  • recv(1024)不代表一定收到1024个字节,而是最多只能收这么多

  • 两条连续发送的数据一定要避免粘包问题

  • 先发送数据的长度 再发送数据

    • 发送的数据相关的内容组成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()
原文地址:https://www.cnblogs.com/iaoyuyuyuhuanghuang/p/14298305.html