网络编程基础粘包现象

粘包

  • tcp是流式传输,字节流,数据与数据之间是没有边界的
    • 流式传输优势:
      • 不限定长度
      • 可靠传输
    • 缺点:
      • 和一我的的通讯链接conn会一直占用咱们的通讯资源
  • udp协议,面向数据包的传输
    • 数据包优势
      • 因为不须要创建链接,因此谁发的消息我都能接受到
    • 缺点
      • 不能传输过长的数据
      • 不可靠

粘包现象

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

解决粘包问题

  • struct模块python

    • 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端dom

  • 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()
相关文章
相关标签/搜索