python-day30--粘包
一、 什么是粘包
1.须知:只有TCP有粘包现象,UDP永远不会粘包
2.所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。
二、两种情况下会发生粘包。
1.发送数据时间间隔很短,数据了很小,会合到一起,产生粘包
from socket import *
import time
phone=socket(AF_INET,SOCK_STREAM)
phone.connect(('127.0.0.1',8080)) phone.send('helloworld'.encode('utf-8'))
phone.send('egon'.encode('utf-8'))
客户端
2.接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
from socket import *
import time
phone=socket(AF_INET,SOCK_STREAM)
phone.connect(('127.0.0.1',8080)) phone.send('helloworld'.encode('utf-8'))
time.sleep(5)
phone.send('egon'.encode('utf-8'))
客户端
from socket import *
phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8080))
phone.listen(5)
conn,client_addr=phone.accept() data1=conn.recv(8)
print('data1: ',data1)
data2=conn.recv(20)
print('data2:',data2)
data3=conn.recv(20)
print('data3:',data3)
# 结果
# data1: b'hellowor'
# data2: b'ld'
# data3: b'egon'
服务端
三、
拆包的发生情况
当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。
补充问题一:为何tcp是可靠传输,udp是不可靠传输
基于tcp的数据传输请参考我的另一篇文章http://www.cnblogs.com/linhaifeng/articles/5937962.html,tcp在数据传输时,发送端先把数据发送到自己的缓存中,然后协议控制将缓存中的数据发往对端,对端返回一个ack=1,发送端则清理缓存中的数据,对端返回ack=0,则重新发送数据,所以tcp是可靠的
而udp发送数据,对端是不会返回确认信息的,因此不可靠
补充问题二:send(字节流)和recv(1024)及sendall
recv里指定的1024意思是从缓存里一次拿出1024个字节的数据
send的字节流是先放入己端缓存,然后由协议控制将缓存内容发往对端,如果待发送的字节流大小大于缓存剩余空间,那么数据丢失,用sendall就会循环调用send,数据不会丢失
四、解决粘包的low比处理方法
import socket
import subprocess
import struct
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8082)) #绑定手机卡
phone.listen(5) #开机 print('starting...')
while True: #链接循环
conn,client_addr=phone.accept() #等电话 (链接,客户的的ip和端口组成的元组)
print('-------->',conn,client_addr)
#收,发消息
while True:#通信循环
try:
cmd=conn.recv(1024)
if not cmd:break #针对linux
#执行cmd命令,拿到cmd的结果,结果应该是bytes类型
#。。。。
res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout=res.stdout.read()
stderr=res.stderr.read()
#先发报头(转成固定长度的bytes类型)
header = struct.pack('i',len(stdout)+len(stderr))
conn.send(header)
#再发送命令的结果5
conn.send(stdout)
conn.send(stderr)
except Exception:
break
conn.close() #挂电话
phone.close() #关机
服务端
import socket
import struct
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
phone.connect(('127.0.0.1',8082)) #绑定手机卡
#发,收消息
while True:
cmd=input('>>: ').strip()
if not cmd:continue
phone.send(cmd.encode('utf-8'))
#先收报头
header_struct=phone.recv(4)
unpack_res = struct.unpack('i', header_struct)
total_size=unpack_res[0]
#再收数据
recv_size=0 #10241=10240+1
total_data=b''
while recv_size < total_size:
recv_data=phone.recv(1024)
recv_size+=len(recv_data)
total_data+=recv_data
print(total_data.decode('gbk'))
phone.close()
客户端
五、完美解决tcp协议粘包问题
import socket
import subprocess
import struct
import json
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8082)) #绑定手机卡
phone.listen(5) #开机 print('starting...')
while True: #链接循环
conn,client_addr=phone.accept() #等电话 (链接,客户的的ip和端口组成的元组)
print('-------->',conn,client_addr) #收,发消息
while True:#通信循环
try:
cmd=conn.recv(1024)
if not cmd:break #针对linux
#执行cmd命令,拿到cmd的结果,结果应该是bytes类型
#。。。。
res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout=res.stdout.read()
stderr=res.stderr.read()
#制作报头
header_dic = {
'total_size': len(stdout)+len(stderr),
'filename': None,
'md5': None} header_json = json.dumps(header_dic)
header_bytes = header_json.encode('utf-8')
#发送阶段
#先发报头长度
conn.send(struct.pack('i',len(header_bytes)))
#再发报头
conn.send(header_bytes) #最后发送命令的结果
conn.send(stdout)
conn.send(stderr)
except Exception:
break
conn.close() #挂电话
phone.close() #关机
服务端
import socket
import struct
import json
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
phone.connect(('127.0.0.1',8082)) #绑定手机卡 #发,收消息
while True:
cmd=input('>>: ').strip()
if not cmd:continue phone.send(cmd.encode('utf-8'))
#先收报头的长度
header_len=struct.unpack('i',phone.recv(4))[0] #再收报头
header_bytes=phone.recv(header_len)
header_json=header_bytes.decode('utf-8')
header_dic=json.loads(header_json)
total_size=header_dic['total_size'] #最后收数据
recv_size=0 #10241=10240+1
total_data=b''
while recv_size < total_size:
recv_data=phone.recv(1024)
recv_size+=len(recv_data)
total_data+=recv_data
print(total_data.decode('gbk'))
phone.close()
客户端
python-day30--粘包的更多相关文章
- Python之粘包
Python之粘包 让我们基于tcp先制作一个远程执行命令的程序(1:执行错误命令 2:执行ls 3:执行ifconfig) 注意注意注意: res=subprocess.Popen(cmd.deco ...
- Python进阶----粘包,解决粘包(旗舰版)
Python进阶----粘包,解决粘包(旗舰版) 一丶粘包 只有TCP有粘包现象,UDP永远不会粘包 什么是粘包 存在于客户端接收数据时,不能一次性收取全部缓冲区中的数据.当下一次再有数据来时 ...
- python 解决粘包问题
客户端发送hello,如果服务端 recv(1) ,那只能接收到 h 这一个字符,然后再recv(1) 一下,可以再接收一个 e , 因为客户端发送的结果长,所以只能把其他的先缓存下来,下次recv的 ...
- Python socket 粘包
目录 1 TCP的三次握手四次挥手 0 1.1 三次握手 1 1.2 四次挥手 2 2 粘包现象 3 2.1 基于TCP制作远程执行命令操作(win服务端) 4 2.1 基于TCP制作远程执行命令操作 ...
- Python socket粘包解决
socket粘包: socket 交互send时,连续处理多个send时会出现粘包,soket会把两条send作为一条send强制发送,会粘在一起. send发送会根据recv定义的数值发送一个固定的 ...
- Python socket粘包问题(最终解决办法)
套接字: 就是将传输层以下的协议封装成子接口 对于应用程序来说只需调用套接字的接口,写出的程序自然是遵循tcp或udp协议的 实现第一个功能个:实现:通过客户端向服务端发送命令,调取windows下面 ...
- Python socket粘包问题(初级解决办法)
server端配置: import socket,subprocess,struct from socket import * server=socket(AF_INET,SOCK_STREAM) s ...
- python socket粘包及实例
1.在linux中经常出现粘包的出现(因为两个send近靠着,造成接受到的数据是在一起的.)解决方法: 在服务端两send的中间中再添加一个recv(),客户端添加一个send(),服务端收到信息确认 ...
- python tcp 粘包问题解决、文件下载等
from socket import * #以下是关于tcp:服务端 和 客户端的小例子#服务端socket_server = socket(AF_INET, SOCK_STREAM) socket_ ...
- python 解决粘包问题的例子(ftp文件的上传与下载)简单版本
服务端 ! /user/bin/env python3 -- coding:utf_8 -- """ Author:Markli # 2019/9/9,16:41 &qu ...
随机推荐
- HTML5 manifest离线缓存技术
干什么用的? 离线缓存为的是第一次请求后,根据manifest文件进行本地缓存,并且在下一次请求后进行展示(若有缓存的话,无需再次进行请求而是直接调用缓存),最根本的感觉是它使得WEB从online可 ...
- oracle计算过程执行时间写法
--在oracle写过程中很多是对数据处理,业务比较繁琐,有的需要结合job定时器使用,这样就需要知道执行过程的大概时间,不废话直接上脚本,统计单位为分钟 PROCEDURE DATA_DEAL_WI ...
- 一个快速检测系统CPU负载的小程序
原理说明 在对服务器进行维护时,有时也遇到由于系统 CPU(利用率)负载过高导致业务中断的情况.服务器上可能运行多个进程,查看单个进程的 CPU 都是正常的,但是整个系统的 CPU 负载可能是异常的. ...
- 响应式瀑布流插件Grid-A-Licious
Grid-A-Licious是一款遵守MIT协议的响应式瀑布流插件.该插件总代码行不超过400行,实现很巧妙,使用时也很流畅.实现原理也很简单,根据屏幕宽度和参数中设置的列宽度以及每项之间的间隔宽度, ...
- Java系列笔记(0) - 目录和概述
笔者在开发过程中发现自己基础太薄弱,读书时除了系统学习了一下Java的基础语法和用法.一点简单的数据结构和设计模式之外,再无深入系统的学习,而工作中的学习也是东晃一枪西晃一枪,不够扎实和系统.想到一个 ...
- 手撕vue-cli配置——webpack.prod.conf.js篇
'use strict' const path = require('path') const utils = require('./utils') const webpack = require(' ...
- loj10009 P1717 钓鱼
P1717 钓鱼 贪心+优先队列 先枚举最后走到哪个湖,然后用优先队列跑一遍贪心即可 #include<iostream> #include<cstdio> #include& ...
- Python3基础 os mkdirs 创建多层文件夹
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- Java8新特性:Function接口和Lambda表达式参考
Lambda基本:https://blog.csdn.net/wargon/article/details/80656575 https://www.cnblogs.com/hyyq/p/742566 ...
- BZOJ5170: Fable 树状数组
Description 有这么一则传闻,O(nlogn)的排序发明之前,滋滋国的排序都是采用的冒泡排序.即使是冒泡排序,对当时的国民 来说也太复杂太难以理解,于是滋滋国出现了这样一个职业——排序使,收 ...