一粘包

  TCP协议是面向对象的,面向流的,提高可靠性服务。使用了优化算法,Nagle算法。将多次间隔较少且数据量小的数据,合并成一个大的数据块,然后进行封包。这样接收端就很难分辨出来。TCP协议数据是可靠的,但是会粘包。

  问题的关键是另一端并不知道你要传多少字节的数据,处理办法是必须先传一个报头,告诉另一端我要发送多少,然后另一端就接收指定数量的字节,这是可以做到的。粘包问题就解决了。

  借助struct模块来解决。

二 struct模块

import struct
res=struct.pack('i',111)
print(res,len(res))
res=struct.pack('i',11111111)
print(res,len(res))

  输出:

b'o\x00\x00\x00' 4
b'\xc7\x8a\xa9\x00' 4

  struct模块对int类型的数字进行字节化,(bytes方法是把字符串类型的字节化),一定范围内的数字字节化后的长度都是4个字节。

import struct
res=struct.pack('i',111) #'i’是表示整数格式
print(res,len(res))
ret=struct.unpack('i',res) #unpack的结果是一个元组
print(ret)
print(ret[0]) #取第一个值,便是pack的整数

  输出:

b'o\x00\x00\x00' 4
(111,)
111

三 彻底解决粘包问题。

  思路:

  A想要给B发送一个字典,这个字典包含filename,filesize,md5等等信息,怎么发送呢

  先用json把字典序列化为字符串,然后字节化。用len方法取其长度 length。这个length就是字典字符串化字节化的长度。

  在用sturct模块,pack方法将上面取到的length,字节化的结果,传给B,这个结果固定长度为4。

  B这边,先recv(4),拿到后,用struct的unpack方法,取到的就是字典字符串化字节化的长度length。

  在recv(length),拿到的就是字典字符串化字节化的结果。这个结果怎么来的就怎么倒回去,decode,json.loads(),拿到字典。拿到filesize。

  while循环,接收长度为filesize的字节。

  到此,粘包问题解决,大功告成。

  

  简言之:

    服务器  1 发送报头的长度。借用struct模块                          客户端     1 接收报头的长度。   recv(4),struct模块unpack取到报头的长度length

         2 发送报头。借用json模块                                                      2 接收报头。              recv(lenth)。json反序列化得到报头。报头中有‘’size‘’

           3 发送真实数据                                                                       3 接收真实数据           报头中含有size,对应真实数据的数据。

            

  客户端:

import socket
import struct
import json
#1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #2、打电话
phone.connect(('127.0.0.1',8092)) #3、发收消息
while True:
cmd=input('>>: ').strip()
if cmd == 'quit':break
if not cmd:continue
phone.send(cmd.encode('utf-8'))
#先收报头长度
obj=phone.recv(4)
header_size=struct.unpack('i',obj)[0] #再收报头
header_bytes=phone.recv(header_size)
header_json=header_bytes.decode('utf-8')
header_dic=json.loads(header_json)
print(header_dic)
#最后循环收真实的数据
total_size=header_dic['total_size']
filename=header_dic['filename'] total_data=b''
recv_size=0
with open(filename,'wb') as f:
while recv_size < total_size:
recv_data=phone.recv(1024)
total_data+=recv_data
recv_size+=len(recv_data)
print(total_data.decode('gbk')) #4、挂电话
phone.close()

 服务端

import socket
import subprocess
import struct
import json
#1、买手机
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #2、绑定手机卡
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('192.168.11.53',8080)) #3、开机
phone.listen(5) #4、等电话连接
print('starting...')
while True: #连接循环
conn,addr=phone.accept()
print('IP:%s,PORT:%s' %(addr[0],addr[1])) #5、收发消息
while True: #通信循环
try:
cmd=conn.recv(1024) #最大收1024
if not cmd:break #针对linux #执行命令
obj=subprocess.Popen(cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout=obj.stdout.read()
stderr=obj.stderr.read()
#制作报头
header_dic = {'filename': 'a.txt',
'total_size': len(stdout)+len(stderr),
'md5': 'asdfa123xvc123'} header_json = json.dumps(header_dic) header_bytes = header_json.encode('utf-8') #先发报头的长度。发送的长度是字典格式的报头经过json化的bytes化处理的长度。经过struct.pack,固定长度为4个字节。
conn.send(struct.pack('i',len(header_bytes)))
#再发送报头。发送的报头是json化,bytes化后的报头。
conn.send(header_bytes)
#最后发送真实数据
conn.send(stdout)
conn.send(stderr)
except Exception:
break #6、挂电话
conn.close() #7、关机
phone.close()

python 粘包问题及解决方法的更多相关文章

  1. 网络编程——TCP协议、UDP协议、socket套接字、粘包问题以及解决方法

    网络编程--TCP协议.UDP协议.socket套接字.粘包问题以及解决方法 TCP协议(流式协议) ​ 当应用程序想通过TCP协议实现远程通信时,彼此之间必须先建立双向通信通道,基于该双向通道实现数 ...

  2. python粘包分析与解决

    TCP与UDP协议 TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的socket,因此 ...

  3. 网络编程 TCP协议:三次握手,四次回收,反馈机制 socket套接字通信 粘包问题与解决方法

    TCP协议:传输协议,基于端口工作 三次握手,四次挥手 TCP协议建立双向通道. 三次握手, 建连接: 1:客户端向服务端发送建立连接的请求 2:服务端返回收到请求的信息给客户端,并且发送往客户端建立 ...

  4. TCP协议的粘包现象和解决方法

    # 粘包现象 # serverimport socket sk = socket.socket()sk.bind(('127.0.0.1', 8005))sk.listen() conn, addr ...

  5. 网络编程----粘包以及粘包问题的解决、FTP上传

    一.粘包现象 让我们基于tcp先制作一个远程执行命令的程序(1:执行错误命令 2:执行ls 3:执行ifconfig) 注意注意: res=subprocess.Popen(cmd.decode('u ...

  6. 什么是TCP粘包?怎么解决这个问题

    在socket网络编程中,都是端到端通信,由客户端端口+服务端端口+客户端IP+服务端IP+传输协议组成的五元组可以明确的标识一条连接.在TCP的socket编程中,发送端和接收端都有成对的socke ...

  7. 在国内使用maven下载jar包非常慢的解决方法

    在国内使用maven下载jar包非常慢的解决方法 1.原因: 很多jar包在国外环境,所以会很慢. 2.解决方法 maven支持镜像环境下载,所以首先找到maven的conf目录中的settings. ...

  8. Python更新pip出现错误解决方法

    Python更新pip出现错误解决方法 更新pip python -m pip install --upgrade pip 查看时报错 解决方法 在命令栏(即win+r)输入:easy_install ...

  9. python cmd 窗口 中文乱码 解决方法 (附:打印不同颜色)

    python cmd 窗口 中文乱码 解决方法 (附:打印不同颜色) 前言 在 python 开发中,有时候想通过cmd窗口来和用户交互,比如显示信息之类的,会比自己创建 GUI 来的方便,但是随之而 ...

随机推荐

  1. jQuery如何获取选中单选按钮radio的值

    使用jquery获取radio的值,最重要的是掌握jquery选择器的使用,在一个表单中我们通常是要获取被选中的那个radio项的值,所以要加checked来筛选,比如有以下的一些radio项: 1. ...

  2. CPP-网络/通信:SSL功能和原理

    面对诸多的网上交易的风险,很多网上银行.网上商城在建立系统时都注意到了安全问题.而我们也经常可以看到很多网上银行.电子商务网站在强调本系统的安全性的时候,都说采用了基于数字证书的SSL加密传输.SSL ...

  3. javaweb基础(8)_HttpServletResponse生成验证码

    一.HttpServletResponse常见应用——生成验证码 1.1.生成随机图片用作验证码 生成图片主要用到了一个BufferedImage类,

  4. Bootstrap历练实例:动画的进度条

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  5. (2) html 语义化

    HTML语义化标签 1 什么是语义化标签? 通过标签判断内容语义,例如根据h1标签判断出内容是标题,根据 p 判断内容是段落.input 标签是输入框等. 2 为什么要标签语义化? 1.搜素引擎友好 ...

  6. NOIP模拟赛 无线通讯网

    [题目描述] 国防部计划用无线网络连接若干个边防哨所.2种不同的通讯技术用来搭建无线网络:每个边防哨所都要配备无线电收发器:有一些哨所还可以增配卫星电话. 任意两个配备了一条卫星电话线路的哨所(两边都 ...

  7. 【细节题 离线 树状数组】luoguP4919 Marisa采蘑菇

    歧义差评:但是和题意理解一样了之后细节依然处理了很久,说明还是水平不够…… 题目描述 Marisa来到了森林之中,看到了一排nn个五颜六色的蘑菇,编号从1-n1−n,这些蘑菇的颜色分别为col[1], ...

  8. Ajax请求出现406的原因

    一般出现406错误有两种可能: 1.如果后缀是html是不能响应json数据的.需要修改后缀名. 在做伪静态化过程中,以.html结尾的后缀,做post请求时,不能响应json格式,这是spring官 ...

  9. vue.js笔记1.0

    事件: 事件冒泡行为: 1.@click="show($event)" show:function (ev) { ev.cancelBubble=true; } 2.@click. ...

  10. machine_desc

    每一个machine,都要定义一个自己的machine_desc结构,该结构定义了该machine的一些最基本的特性. struct machine_desc { unsigned int nr; / ...