一粘包

  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. Sublime 安装Boxy + OmniMarkupPreviewer

    Sublime 安装Boxy + OmniMarkupPreviewer Package Install 安装 网络安装 ctrl+反引号打开控制台,在控制台中输入代码 import urllib.r ...

  2. JQuery EasyUI学习记录(三)

    1.jQuery EasyUI messager使用方式 1.1 alert方法 $(function(){ //1.alert方法---提示框 $.messager.alert("标题&q ...

  3. tensorflow目标检测API之训练自己的数据集

    1.训练文件的配置 将生成的csv和record文件都放在新建的mydata文件夹下,并打开object_detection文件夹下的data文件夹,复制一个后缀为.pbtxt的文件到mtdata文件 ...

  4. spring boot自动配置实现

    自从用了spring boot,都忘记spring mvc中的xml配置是个什么东西了,再也回不去.为啥spring boot这么好用呢, 约定大于配置的设计初衷, 让我们只知道维护好applicat ...

  5. python 爬取知乎图片

    先上完整代码 import requests import time import datetime import os import json import uuid from pyquery im ...

  6. 【android】安卓平台版本和API版本的对应关系

    安卓平台版本和API版本对应关系

  7. 用decimal模块增加python的浮点数精度

    浮点数python默认是17位精度,也就是小数点后16位(16位以后的全部四舍五入了),虽然有16位,但是这个精度越往后越不准. 如果有特殊需求,需要更多的精度,可以用decimal模块,通过更改其里 ...

  8. OpenStack, kvm, qemu-kvm以及libvirt之关系

    OpenStack, kvm, qemu-kvm以及libvirt之关系: KVM是最底层的hypervisor,它是用来模拟CPU的运行,它缺少了对network和周边I/O的支持,所以我们是没法直 ...

  9. csapp-15213错误修正18-10-28

    1.p229 练习题3.15 b.答案错误,应为400419

  10. OpenSSL version mismatch. Built against 1000105f, you have 10001060

    http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=732940 http://ftp.debian.org/debian/pool/main/o/ope ...