一、什么是TCP粘包

  C/S架构下,接收方不知道每个消息的发送间隙、也不知道每次应该提取多少个字节的数据,与此同时,TCP是面向连接的,面向流的,收发两端都要有,因此发送端为了将多个发往接收端的数据包更高效的发给对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个发送给接收端。此时接收端无法分辨出来,必须提供合理的拆包机制,即面向流的通信是无消息保护边界的。
  除此之外,因为TCP是基于流的,所以收发的消息不能为空,需要发送、接收端添加空消息处理机制,防止程序卡住。

二、处理思路

   粘包现象主要是因为发送端没有确切的发送间隔以及发送数据包的大小,而接收端更不知道发送算发送了多少个数据包以及大小,只能来多少接收多少。
   解决方法:
    自定义报头,发送端发送数据之前,先将自定义的报头(数据包大小等信息)发送给接收端,接收端明确每个数据包的大小进行依次接收。

三、实现方式

方法一:

 # 客户端
import socket
import struct IP = '127.0.0.1'
PORT = 8080
bufsize = 1024 client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client_socket.connect((IP,PORT)) while True:
cmd = input('cmd>>>').strip()
if len(cmd) == 0:continue
elif cmd == 'q':break client_socket.send(cmd.encode('utf-8')) # 1.接收固定报头
header = client_socket.recv(4) # 2.解析报头
total_size = struct.unpack('i',header)[0]
print(total_size) # 3.根据包头接收真实数据
recv_size = 0
# 保存接收的数据(接收到的是byte类型)
res_data = b''
while recv_size < total_size:
recv_data = client_socket.recv(1024)
res_data += recv_data
recv_size += len(recv_data) print(recv_data.decode('gbk')) client_socket.close() # 服务端
import socket
import subprocess
import struct IP = '127.0.0.1'
PORT = 8080
bufsize = 1024 tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_socket.bind((IP,PORT),)
tcp_socket.listen(5) while True:
conn,addr = tcp_socket.accept()
print('客户端:',addr) while True:
try:
cmd = conn.recv(bufsize)
res = subprocess.Popen(cmd.decode('utf-8'),shell=True
,stdin=subprocess.PIPE
,stdout=subprocess.PIPE
,stderr=subprocess.PIPE)
stderr = res.stderr.read()
stdout = res.stdout.read() # 1.制作固定长度的报头
total_size = len(stdout) + len(stderr)
header = struct.pack('i',total_size) # 2.发送报头
conn.send(header) # 3.发送真实数据
conn.send(stderr)
conn.send(stdout)
except ConnectionResetError:
break
conn.close()
tcp_socket.close()

解决粘包问题

方法二:

 # 客户端
import socket
import struct
import json IP = '127.0.0.1'
PORT = 8080
bufsize = 1024 client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client_socket.connect((IP,PORT)) while True:
cmd = input('cmd>>>').strip()
if len(cmd) == 0:continue
elif cmd == 'q':break client_socket.send(cmd.encode('utf-8')) # 1.接收包头长度
header_size = struct.unpack('i',client_socket.recv(4))[0] # 2.接收报头
header_bytes = client_socket.recv(header_size) # 3.解析报头
header_json = header_bytes.decode('utf-8')
header_dic = json.loads(header_json)
# print(header_dic) total_size = header_dic['total_size'] # 3.根据包头接收真实数据
recv_size = 0
# 保存接收的数据(接收到的是byte类型)
res_data = b''
while recv_size < total_size:
recv_data = client_socket.recv(1024)
res_data += recv_data
recv_size += len(recv_data) print(recv_data.decode('gbk')) client_socket.close() # 服务端
import socket
import subprocess
import struct
import json IP = '127.0.0.1'
PORT = 8080
bufsize = 1024 tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_socket.bind((IP,PORT),)
tcp_socket.listen(5) while True:
conn,addr = tcp_socket.accept()
print('客户端:',addr) while True:
try:
cmd = conn.recv(bufsize)
res = subprocess.Popen(cmd.decode('utf-8'),shell=True
,stdin=subprocess.PIPE
,stdout=subprocess.PIPE
,stderr=subprocess.PIPE)
stderr = res.stderr.read()
stdout = res.stdout.read() # 1.制作固定长度的报头
header_dic = {
'total_size':len(stdout) + len(stderr),
'md5':'123sssss222',
'filename':'120.txt'} header_json = json.dumps(header_dic)
header_bytes = header_json.encode('utf-8') # 2.发送报头的长度
total_size = len(header_bytes)
conn.send(struct.pack('i',total_size)) # 发送报头
conn.send(header_bytes) # 3.发送真实数据
conn.send(stderr)
conn.send(stdout)
except ConnectionResetError:
break
conn.close()
tcp_socket.close()

解决粘包问题

Python全栈-网络编程-TCP粘包的更多相关文章

  1. Python之路 - 网络编程之粘包

    Python之路 - 网络编程之粘包 粘包

  2. Python全栈-网络编程基础

    一.C/S架构 1.硬件C/S架构 如PC-打印机 2.软件C/S架构 如PC-网站服务器 参照: https://baike.baidu.com/item/Client%2FServer/15044 ...

  3. python套接字解决tcp粘包问题

    python套接字解决tcp粘包问题 目录 什么是粘包 演示粘包现象 解决粘包 实际应用 什么是粘包 首先只有tcp有粘包现象,udp没有粘包 socket收发消息的原理 发送端可以是一K一K地发送数 ...

  4. 8-2udp和tcp网络编程以及粘包和解决粘包的方法

    一  tcp网络编程 server 端 import socket sk=socket.socket() #实例化一个对象 sk.setsockopt(socket.SOL_SOCKET,socket ...

  5. python语法基础-网络编程-TCP协议和UDP协议

    ###############    网络编程    ############## """ 网络编程 学习了Python基础之后,包括函数,面向对象等,你就可以开发了,你 ...

  6. socket编程 TCP 粘包和半包 的问题及解决办法

    一般在socket处理大数据量传输的时候会产生粘包和半包问题,有的时候tcp为了提高效率会缓冲N个包后再一起发出去,这个与缓存和网络有关系. 粘包 为x.5个包 半包 为0.5个包 由于网络原因 一次 ...

  7. python socket网络编程之粘包问题详解

    一,粘包问题详情 1,只有TCP有粘包现象,UDP永远不会粘包 你的程序实际上无权直接操作网卡的,你操作网卡都是通过操作系统给用户程序暴露出来的接口,那每次你的程序要给远程发数据时,其实是先把数据从用 ...

  8. Python网络编程,粘包、分包问题的解决

    tcp编程中的粘包.分包问题的解决: 参考:https://blog.csdn.net/yannanxiu/article/details/52096465 服务端: #!/bin/env pytho ...

  9. python网络编程之粘包

    一.什么是粘包 须知:只有TCP有粘包现象,UDP永远不会粘包 粘包不一定会发生 如果发生了:1.可能是在客户端已经粘了 2.客户端没有粘,可能是在服务端粘了 首先需要掌握一个socket收发消息的原 ...

随机推荐

  1. Java之旅_高级教程_URL处理

    摘自 :http://www.runoob.com/java/java-url-processing.html Java URL 处理 URL(Uniform Resource Locator)中文名 ...

  2. Java基础知识(JAVA集合框架之List与Set)

    List和Set概述数组必须存放同一种元素.StringBuffer必须转换成字符串才能使用,如果想拿出单独的一个元素几乎不可能.数据有很多使用对象存,对象有很多,使用集合存. 集合容器因为内部的数据 ...

  3. Python3学习之路~6.6 类的继承

    Inheritance 继承 面向对象编程 (OOP) 语言的一个主要功能就是“继承”.继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展.通过继承创 ...

  4. 协程.md

    一. # 可迭代l = [ i for i in range(10) ] # l是可迭代的,但不是迭代器for idx in l:    print(idx)    # range是个迭代器for i ...

  5. HTTP response 添加body

    在拦截器中进行拦截操作时,想要给response添加body,如何操作? /** * 返回JSON数据 * @param response * @param obj * @throws Excepti ...

  6. abap调用代码块

    1:abap 调用代码块. *&---------------------------------------------------------------------* *& Re ...

  7. [py]Python使用UUID库生成唯一ID(uuid模块)

    https://www.cnblogs.com/dkblog/archive/2011/10/10/2205200.html uuid介绍 UUID是128位的全局唯一标识符,通常由32字节的字符串表 ...

  8. finally最常用的情况

    通常用于关闭(释放)资源例如:数据库连接   执行查询时查到需要的需要后   需要关闭连接,   此处连接就需要在获取到结果后 就断开连接   不然访问人数过多,数据库有最大连接数,超过了就只能等待前 ...

  9. Py中enumerate方法【转载】

    转自:http://www.runoob.com/python/python-func-enumerate.html enumerate(sequence, [start=0]) sequence - ...

  10. mybatis 调用oracle存储过程如何返回out参数值

    调试了半天,其实整体用map传入传出也挺简单, 主要是调用存储过程 select标签里平时习惯不写 statementType="CALLABLE",调用没有out参数时也能正常用 ...