zoukankan      html  css  js  c++  java
  • 网络编程基础粘包现象

    粘包

    • tcp是流式传输,字节流,数据与数据之间是没有边界的
      • 流式传输优点:
        • 不限定长度
        • 可靠传输
      • 缺点:
        • 和一个人的通信连接conn会一直占用我们的通信资源
    • udp协议,面向数据包的传输
      • 数据包优点
        • 由于不需要建立连接,所以谁发的消息我都能接受到
      • 缺点
        • 不能传输过长的数据
        • 不可靠

    粘包现象

    • 由于流式传输的特点,产生了数据连续发送的粘包现象。
      • 在一个conn建立起来的连接上传输的多条数据是没有边界的
    • 数据的发送和接收实际上不是在执行send/recv的时候就立刻被发送和接收,而是需要经过操作系统内核
    • Nagle 算法,能够将发送间隔实际很近的短数据合成一个包发送到接收端
    • 拆包机制: 当要发送的数据超过了网络上能够传输的最大长度,就会被tcp协议强制拆包

    解决粘包问题

    • struct模块

      • park("i",len(msg)) 把数字转成4字节

      • unpack("i",bytes)[0] 把四字节转换成长度

      • server端
        import struct
        import socket
        
        sk = socket.socket()
        sk.bind(('127.0.0.1',9090))
        sk.listen()
        
        conn,addr = sk.accept()
        while True:
            s = input('>>>').encode('utf-8')
            pack_num = struct.pack('i',len(s))
            conn.send(pack_num)
            conn.send(s)
        conn.close()
        sk.close()
        
      • client端
        import socket
        import struct
        sk = socket.socket()
        sk.connect(('127.0.0.1',9090))
        
        while True:
            pack_num = sk.recv(4)
            num = struct.unpack('i',pack_num)[0]
            ret = sk.recv(num)
            print(ret.decode('utf-8'))
        sk.close()
        

    并发的 socketserver

    • 实现同一时刻server端可以和多个client端建立连接

    验证客户端链接的合法性

    • server端

    • import os
      import hmac
      import socket
      def auth(conn):
          msg = os.urandom(32)  # # 生成一个随机的字符串
          conn.send(msg)  # # 发送到client端
          result = hmac.new(secret_key, msg)  # 处理这个随机字符串,得到一个结果
          client_digest = conn.recv(1024)  # 接收client端处理的结果
          if result.hexdigest() == client_digest.decode('utf-8'):
              print('是合法的连接')  # 对比成功可以继续通信
              return True
          else:
              print('不合法的连接')  # 不成功 close
              return False
      secret_key = b'alex_sb'
      sk = socket.socket()
      sk.bind(('127.0.0.1',9000))
      sk.listen()
      conn,addr = sk.accept()
      if auth(conn):
          print(conn.recv(1024))
          # 正常的和client端进行沟通了
          conn.close()
      else:
          conn.close()
      sk.close()
      
    • client端

    • import hmac
      import socket
      def auth(sk):
          msg = sk.recv(32)
          result = hmac.new(key, msg)
          res = result.hexdigest()
          sk.send(res.encode('utf-8'))
      
      key = b'alex_s'
      sk = socket.socket()
      sk.connect(('127.0.0.1',9000))
      auth(sk)
      sk.send(b'upload')
      # 进行其他正常的和server端的沟通
      sk.close()
      
  • 相关阅读:
    Idea配置注释
    mysql省市区数据表
    php实现汉字转拼音的类
    git push时如果不再弹出用户和密码的输入提示框该怎么办
    .gitignore 忽略特殊文件无效
    vmware中CentOS7网络设置教程详解
    Tp5中配置多模块开发
    安装tp6 并使用多应用模式
    ldf和mdf文件怎么还原到sqlserver数据库
    git本地仓库与远程仓库建立连接。
  • 原文地址:https://www.cnblogs.com/yuncong/p/9665453.html
Copyright © 2011-2022 走看看