zoukankan      html  css  js  c++  java
  • 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()
  • 相关阅读:
    事件使用(转 )
    使用Dotfuscator 进行.Net代码混淆 代码加密的方法
    Git分布式版本控制系统学习笔记
    免费SVN服务器笔记
    如何设置mysql远程访问及防火墙设置
    c# GridControl怎么换行
    模拟Post登陆带验证码的网站
    c#控制打印机杂项
    ssh 自动登录
    mysql 使用记号
  • 原文地址:https://www.cnblogs.com/iaoyuyuyuhuanghuang/p/14298305.html
Copyright © 2011-2022 走看看