• TCP协议的黏包问题与解决方法:


    黏包:接收到的数据包乱了,有部分本次请求的数据临时存入了缓冲区,导致下次请求时一起显示

    TCP协议会黏包,但是不会丢包

    UDP协议不会黏包,但可能丢包

    TCP黏包原因:1.多个send连在一起发送,且数据量小  2.多个recv接收,第一个数据量小   

    本质上是TCP算法进行了内部优化 一个单位时间内,连续发送较小数据包会默认合并发送,降低多次发送的延时

    为什么会黏包:

    因为tcp是面向流的协议,在数据发送传输中有缓存机制来避免数据丢失,连续发送接收小数据时会黏包,根本是不知道接收数据的大小

    ****************************************************************************************

    服务器端:

     1 import socket
     2 sk=socket.socket()
     3 sk.bind(('127.0.0.1',8080))
     4 sk.listen()
     5 
     6 conn,addr=sk.accept()
     7 while True:
     8     cmd=input('请输入...')
     9     if cmd=='q':
    10         conn.send(b'q')
    11         break
    12     conn.send(cmd.encode('gbk'))
    13     long=conn.recv(1024).decode('utf-8')
    14     conn.send(b'ok')  #服务器确认收到
    15 
    16     res=conn.recv(int(long)).decode('gbk')
    17     print(res)
    18 conn.close()
    19 sk.close()

    客户端:

     1 import socket
     2 import subprocess
     3 sk=socket.socket()
     4 
     5 sk.connect(('127.0.0.1',8080))
     6 while True:
     7     cmd=sk.recv(1024).decode('gbk')
     8     if cmd=='q':
     9         sk.send(b'q')
    10         break
    11     res=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    12     stdout=res.stdout.read()
    13     stderr=res.stderr.read()
    14     sk.send(str(len(stdout)+len(stderr)).encode('utf-8')) #告诉服务器要接收数据的长度
    15     sk.recv(1024)
    16     sk.send(stdout)
    17     sk.send(stderr)
    18 sk.close()

     但是上述代码额外增加了一次send和recv 数据阻塞的时间延长了

    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    用struct模块可以省去这次不必要的数据发送

    struct可以将各种数据类型转为byte类型  struct.pack(‘i’,num)  i模式代表int类型 转为byte 通常为4个字节

    struct.pack(‘i’,num)包装    struct.unpack(‘i’,num)[0]  还原 为元组形式取第一个元素就是值

    server:

     1 import struct
     2 import socket
     3 sk=socket.socket()
     4 sk.bind(('127.0.0.1',8080))
     5 sk.listen()
     6 
     7 conn,addr=sk.accept()
     8 while True:
     9     cmd=input('请输入...')
    10     if cmd=='q':
    11         conn.send(b'q')
    12         break
    13     conn.send(cmd.encode('gbk'))
    14     long=conn.recv(4)
    15     long=struct.unpack('i',long)[0]     #取元组的第一个元素
    16 
    17     res=conn.recv(long).decode('gbk')
    18     print(res)
    19 conn.close()
    20 sk.close()

    client:

     1 import struct
     2 import socket
     3 import subprocess
     4 sk=socket.socket()
     5 
     6 sk.connect(('127.0.0.1',8080))
     7 while True:
     8     cmd=sk.recv(1024).decode('gbk')
     9     if cmd=='q':
    10         sk.send(b'q')
    11         break
    12     res=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    13     stdout=res.stdout.read()
    14     stderr=res.stderr.read()
    15     long=len(stdout)+len(stderr)
    16     long=struct.pack('i',long)
    17     sk.send(long) #告诉服务器要接收数据的长度 数字为4字节
    18     
    19     sk.send(stdout)
    20     sk.send(stderr)
    21 sk.close()
  • 相关阅读:
    吐槽接口文档(二)——什么是优秀的接口文档
    吐槽接口文档(一)——什么是合格的接口文档
    Java 串口通讯库
    Istio快速入门
    Neo4j删除节点和关系、彻底删除节点标签名
    [Neo4j] 在neo4j中批量创建节点和关系
    neo4j︱Cypher完整案例csv导入、关系联通、高级查询(三)
    neo4j︱Cypher 查询语言简单案例(二)
    neo4j︱图数据库基本概念、操作罗列与整理(一)
    neo4j设置节点或者边的显示,包括颜色、属性、大小
  • 原文地址:https://www.cnblogs.com/wen-kang/p/9393324.html
Copyright © 2020-2023  润新知