一、粘包问题

问题1: 无法确认对方发送过来数据的大小。

‘client.py'

import socket

client = socket.socket()

client.connect(
('127.0.0.1', 9000)
) while True: cmd = input('客户端输入的内容: ') client.send(cmd.encode('utf-8')) data = client.recv(19190)
print(len(data))
print(data.decode('gbk'))

‘server.py'

import socket
import subprocess server = socket.socket()
server.bind(('127.0.0.1',9000))
server.listen(5) while True:
conn,addr = server.accept()
print(addr)
while True:
try:
cmd = conn.recv(10)
if len(cmd) == 0:
continue
cmd = cmd.decode('utf-8') #utf8
if cmd == 'q':
break
#调用subprocess连接终端,对终端进行操作,并获取操作后正确或错误的结果
obj = subprocess.Popen(
#cmd接受的是解码后的字符串
cmd,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
#结果交给result变量名
result = obj.stdout.read()+obj.stderr.read()
print(len(result))
print(result.decode('gbk')) #windows系统下默认编码gbk
#将结果返回给客户端
conn.send(result) except Exception as e:
print(e)
break
conn.close()

问题2: 在发送数据间隔短并且数据量小的情况下,会将所有数据一次性发送。

‘client.py'

import socket

client = socket.socket()

client.connect(
('127.0.0.1', 9000)
) client.send(b'hello')
client.send(b'hello')
client.send(b'hello')

‘server.py'

import socket

server = socket.socket()

server.bind(
('127.0.0.1', 9000)
) server.listen(5) conn, addr = server.accept() data = conn.recv(5)
print(data) # b'hello' data = conn.recv(1024)
print(data) # b'hello' data = conn.recv(1024)
print(data) # b'hello'

二、粘包问题的解决方案:

粘包问题的解决方案: 确认对方数据的大小。

这里需要用 struct模块

struct是什么?

是一个python内置的模块,它可以将固定长度的数据,打包成固定格式的长度。

固定格式:如 “ i ” 模式

i : 4

struct作用:

可以将真实数据,做成一个固定长度的报头,客户端发送给服务器,服务器可以接受报头,然后对报头进行解包,获取真实数据的长度,进行接收即可

import struct

data = b'1111111111111111'
print(len(data)) #16 #打包制作报头
header = struct.pack('i',len(data))
print(header) #b'\x10\x00\x00\x00'
print(len(header)) #4 #解包获取真实数据长度 --->得到一个元组,元组中第一个值是真实数据的长度
res = struct.unpack('i',header)[0]
print(res) #16

无论哪一端先发送数据

  • 客户端

    - 1) 先制作报头,并发送 (struct)

    - 2) 发送真实数据

  • 服务端:

    - 1) 接收报头,并解包获取 真实数据长度

    - 2) 根据真实数据长度 接收真实数据

    recv(真实数据长度)

简单版:

‘client.py'

import socket
import struct client = socket.socket()
client.connect(('127.0.0.1', 9000)) while True:
cmd = input('客户端输入的内容: ')
cmd_bytes = cmd.encode('utf-8') header = struct.pack('i',len(cmd_bytes)) #做一个报头
print(len(header)) #打印报头的长度
client.send(header) #发送报头
client.send(cmd_bytes) #待服务端确认长度后,发送真实数据长度 headers = client.recv(4) #接受服务端的报头
data_len = struct.unpack('i',headers)[0] #解包
result = client.recv(data_len) #接受服务器返回的真实数据的长度 print('接受服务器返回的真实数据的长度',len(result))
print(result.decode('gbk'))

‘server.py'

import socket
import subprocess
import struct server = socket.socket()
server.bind(('127.0.0.1',9000))
server.listen(5) while True:
conn,addr = server.accept()
print(addr)
while True:
try:
header = conn.recv(10) #获取客户端传过来的报头
data_len = struct.unpack('i',header)[0] #解包获取真实数据的长度
cmd = conn.recv(data_len) #准备接受真实数据 if len(cmd) == 0:
continue
cmd = cmd.decode('utf-8')
if cmd == 'q':
break
#调用subprocess连接终端,对终端进行操作,并获取操作后正确或错误的结果
obj = subprocess.Popen(
#cmd接受的是解码后的字符串
cmd,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
result = obj.stdout.read()+obj.stderr.read() #获取结果
print('发送给服务端返回的真实数据的长度', len(result))
header = struct.pack('i', len(result)) #做报头
print(len(header))
conn.send(header) #发送报头给客户端
conn.send(result) #将结果返回给客户端 except Exception as e:
print(e)
break
conn.close()

序列化版:

‘client.py'

import socket,json
import struct client = socket.socket()
client.connect(('127.0.0.1',9000))
while True:
movie_name = input('请输入上传的电影名字:') #伪装电影的真实数据
movie = 1000000
send_dic ={'movie_name':movie_name,
'movie':movie}
#序列化
json = json.dumps(send_dic)
print(json)
print(json.encode('utf-8'))
print(len(json.encode('utf-8')))
json_bytes = json.encode('utf-8') #做一个报头
header = struct.pack('i',len(json_bytes))
#先发送报头
client.send(header)
#再发送真实数据
client.send(json_bytes)

‘server.py'

import socket,json
import struct server = socket.socket()
server.bind(('127.0.0.1',9000))
server.listen(5) while True:
conn,addr = server.accept()
while True:
try:
#获取客户端传过来的报头
header = conn.recv(4)
#解包获取真实数据的长度
json_len = struct.unpack('i',header)[0]
#接受json(dic)的真实数据
json_bytes_data = conn.recv(json_len)
#将bytes类型数据转为json数据类型
json_data = json_bytes_data.decode('utf-8')
#反序列化 json--->dict
back_dic = json.loads(json_data)
print(back_dic)
print(back_dic.get('movie')) except Exception as e:
print(e)
break
conn.close()

socket粘包问题及解决方案的更多相关文章

  1. Socket粘包问题终极解决方案—Netty版(2W字)!

    上一篇我们讲了<Socket粘包问题的3种解决方案>,但没想到评论区竟然炸了.介于大家的热情讨论,以及不同的反馈意见,本文就来做一个扩展和延伸,试图找到问题的最优解,以及消息通讯的最优解决 ...

  2. UNIX网络编程——tcp流协议产生的粘包问题和解决方案

    我们在前面曾经说过,发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体 ...

  3. Python socket粘包解决

    socket粘包: socket 交互send时,连续处理多个send时会出现粘包,soket会把两条send作为一条send强制发送,会粘在一起. send发送会根据recv定义的数值发送一个固定的 ...

  4. python 全栈开发,Day35(TCP协议 粘包现象 和解决方案)

    一.TCP协议 粘包现象 和解决方案 黏包现象让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)执行远程命令的模块 需要用到模块subprocess sub ...

  5. socket粘包现象加解决办法

    socket粘包现象分析与解决方案 简单远程执行命令程序开发(内容回顾) res = subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=su ...

  6. Socket粘包问题

    这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...

  7. C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)

    介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解 ...

  8. [转]关于Socket粘包问题

    这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...

  9. 解决Socket粘包问题——C#代码

    解决Socket粘包问题——C#代码 前天晚上,曾经的一个同事问我socket发送消息如果太频繁接收方就会有消息重叠,因为当时在外面,没有多加思考 第一反应还以为是多线程导致的数据不同步导致的,让他加 ...

随机推荐

  1. 阿里云:面向5G时代的物联网无线连接服务

    在4月24日落幕的2019中国联通合作伙伴大会“5G+物联网(IoT)论坛”上,阿里云高级运营专家李茁出席圆桌对话,分享了5G时代物联网如何更好地推动行业完成生产.管理和商业模式的创新,阿里云又会以何 ...

  2. Libev源码分析08:Libev中的内存扩容方法

    在Libev中,如果某种结构的数组需要扩容,它使用array_needsize宏进行处理,比如: array_needsize (int, fdchanges, fdchangemax, fdchan ...

  3. hdu 2312 Cliff Climbing (pfs)

    Problem - 2312 一条很暴力,有点恶心的搜索.题意其实很简单,主要是pfs的时候拓展结点会有种麻烦的感觉.注意的是,这里的n和m跟平常见到的有所不同,交换过来了.我的代码就是在因为这个长宽 ...

  4. STS Eclipse IDEA 指定启动JDK版本

    使用场景: 开发人员在自己的机器上可能装了多个版本的JDK,但是在环境变量中只能配置一个 JAVA_HOME ,so你的IDEA Eclipse 可能因为你在 JAVA_HOME 配置JDK1.8 以 ...

  5. 【t079】火星上的加法运算

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 最近欢欢看到一本有关火星的书籍,其中她被一个加法运算所困惑,由于她的运算水平有限,想向你求助,作为一名 ...

  6. python开启GPU加速

    看了好多教程都提到了使用 os.environ["CUDA_VISIBLE_DEVICES"] = "1" 或者export CUDA_VISIBLE_DEVI ...

  7. springboot 实现 aop

    pom.xml 导入 springboot aop 依赖 <dependency> <groupId>org.springframework.boot</groupId& ...

  8. git查看当前分支所属

    1.git branch -vv 2.git config --lis

  9. java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to com.etc.service.serviceImpl.BankServiceImpl

    错误原因: java.lang.ClassCastException: com.sun.proxy.$Proxy6 cannot be cast to com.etc.service.serviceI ...

  10. C# winforms 输入颜色转换颜色名

    本文告诉大家如何输入颜色,如0xFFFF8000转换为 Orange 在 winforms 程序 可以使用下面代码转换 public static class HexColorTranslator { ...