zoukankan      html  css  js  c++  java
  • 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()
  • 相关阅读:
    全新的ASP.NET !
    asp.net core+ef core
    直播服务器Nginx
    NET Core1
    网络爬虫1
    java thread reuse(good)
    java中Executor、ExecutorService、ThreadPoolExecutor介绍(转)
    小心LinkedHashMap的get()方法(转)
    LinkedHashMap相关信息介绍(转)
    HashTable和HashMap的区别
  • 原文地址:https://www.cnblogs.com/wen-kang/p/9393324.html
Copyright © 2011-2022 走看看