每个socket被创建以后,都会分配两个缓冲区,输入缓冲区和输出缓冲区,默认大小都是8k,可以通过getsocket()获取,暂时存放传输数据,防止程序在发送的时候卡阻,提高代码运行效率.
import subprocess
sub_obj = subprocess.Popen(
'ls', #系统命令
shell = True, #固定格式
stdout=subprocess.PIPE, #标准输出 PIPE管道,保存着指令的执行结果
stderr=subprocess.PIPE #标准错误输出
)
print('正确输出',sub_obj.stdout.read().decode('gbk'))
print('错误输出',sub_obj.stderr.read().decode('gbk'))
#测试byte长度
# print(len(b'hello'))
# print(bytes(str(2),encoding='utf-8'))

1.tcp两种黏包现象:
a. 发送端需要等缓冲区满了才发送出去,造成黏包(发送时间的间隔很短,数据也很小,会被底层优化算法河道一起,产生黏包现象)
server端的代码示例额如下:
from socket import *
ip_port = ('127.0.0.1',8080)
tcp_socket_server =socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen()
conn,addr = tcp_socket_server.accept()
#服务端连接接收两个信息
data1=conn.recv(10)
data2=conn.recv(10)
print('------>',data1.decode('utf-8'))
print('------>',data2.decode('utf-8'))
conn.close()
client端的实例如下:
import socket
BUFSIZE= 1024
ip_port = ('127.0.0.1',8080)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res = s.connect(ip_port)
s.send('hi'.encode('utf-8'))
s.send('meinv'.encode('utf-8'))
b. 接受方没有及时接受缓冲区的包,导致多个包接受,(客户端发送一段数据,服务端只收了一小部分,服务区 下次接受的时候还是从缓冲区拿上次遗留的数据,产生黏包)第一次如果发送的数据大小2000B,接受端一次性接受大小为1024,这样就导致剩下的内容会被下一次recv接收到,导致结果的错乱.
server端的代码示例额如下:
import socket
import subprocess
server = socket.socket()
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn, addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024)
print(from_client_cmd.decode('utf-8'))
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
std_msg = sub_obj.stdout.read()
print('指令的执行结果长度>>>>',len(std_msg))
conn.send(std_msg)
client端的实例如下:
import socket
client = socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
cmd = input("请输入指令:")
client.send(cmd.encode('utf-8'))
server_cmd_result = client.recv(1024)
print(server_cmd_result.decode('gbk'))
解决tcp黏包的方案有两种,第一种是了解一下,第二种是必须记住.
1.方案一:由于接受方不知道发送端将要传送的自接力的长度,导致接收的尾喉,可能接收不全,或者多接收另外一次发送的内容,把自己将要送的字节流总大小让对方知晓,然后接收方发一个确认消息给发送端,然后发送端在发送过来后面的真实数据,接收方在来呢接收完
server端的代码示例额如下:
import socket
import subprocess
server = socket.socket( )
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024)
print(from_client_cmd.decode('utf-8'))#接收到客户端发送来的系统指令,我服务端通过subprocess模块到服务端自己的系统里面执行这条指令
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE, #正确结果的存放的位置
stderr=subprocess.PIPE #错误结果的存放的位置
)
# 从管道里面拿结果,通过subprocess.Popen的实例化对象.stdout.read()方法来获取管道中的结果
std_msg = sub_obj.stdout.read()
#为了解决黏包现象,我们统计一下消息的长度,现将消息的长度发送给客户端,客户端通过这个长度来接收后面我们要发送的真实数据
std_msg_len = len(std_msg)
#首先将数据长度的数据类型装换成bytes类型
std_bytes_len = str(len(std_msg)).encode('utf-8')
print('指令的执行结果长度>>>>>:',len(std_msg))
conn.send(std_bytes_len)
status = conn.recv(1024)
if status.decode('utf-8') == 'ok':
conn.send(std_msg)
else:
pass
client端的实例如下:
import socket
client = socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
cmd = input('请输入指令:')
client.send(cmd.encode('utf-8'))
server_res_len = client.recv(1024).decode('utf-8')
print('来自服务端的消息长度',server_res_len)
client.send(b'ok')
server_cmd_result = client.recv(int(server_res_len))
print(server_cmd_result.decode('gbk'))`
2.方案二: 通过struck模块将需要发送的内容长度进行打包,打包成一个4字节长度的数据发送到对端,对端只要取出前4个字节,然后对前4个字节的数据进行捷豹,拿到发送的长度,然后通过这个长度来继续接受我们要发送的内容.
struck模块的使用:struck模块中最重的两个函数就是pack()打包,unpack()解包

pack(): 我们这里只介绍'i'这个int类型,上面的途中列举了处理可以打包的所有的数据类型,并且struck处理pack和unpack两个方法之外还有好多别的方法和用法.
import struct
num = 100
# num太大的话会报错,
# struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围
# 打包,将int类型的数据打包成4个长度的bytes类型的数据
byt = struct.pack('i',num)
print(byt)
# 解包,将bytes类型的数据,转换为对应的那个int类型的数据
# 注:unpack返回的是truple
int_num = struct.unpack('i',byt)[0]
print(int_num)
解决黏包现象的第二种方案:
服务端:
import socket
import subprocess
import struct
server = socket.socket()
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024)
print(from_client_cmd.decode('utf-8'))
#接收到客户端发送过来的系统指令,我服务端通过subprocess模块到服务端自己的系统里面执行这条指令
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE, #正确结果的存放位置
stderr=subprocess.PIPE #错误结果的存放位置
)
# 从管道里面拿出结果,通过subprocess.Popen的实例化对象.stdout.read()方法来获取管道中的结果
std_msg = sub_obj.stdout.read()
#为了解决黏包现象,我们统计了一下消息的长度,先将消息的长度发送给客户端,客户端通过这个长度来接收后面我们要发送的真实的数据
std_msg_len = len(std_msg)
print('指令的执行结果长度>>>>>>',len(std_msg))
msg_lenint_struct =struct.pack('i',std_msg_len)
conn.send(msg_lenint_struct+std_msg)
客户端:
import socket
import struct
client = socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
cmd = input('请输入指令:')
#发送指令
client.send(cmd.encode('utf-8'))
#接收数据长度,首先接收4个字节长度的数据,因为这个4个字节是长度
server_res_len=client.recv(4)
msg_len= struct.unpack('i',server_res_len)[0]
print('来自服务端的消息长度',msg_len)
#通过解包出来的长度,来接收后面的真实数据
server_cmd_result =client.recv(msg_len)
print(server_cmd_result.decode('gbk'))
查看自己的缓存的大小
# print(server.getsockopt(socket.SOL_SOCKET,socket.SO_SNDBUF))
# print(server.getsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF))
3. udp是面向包的,所以udp是不存在黏包的。
在udp代码中,我们在server端接受返回消息的时候,我们设置的recvfrom(1024),那么当我们输入的执行指令为'dir'的时候,若dir在当前文件夹下输出的内容大于1024,然后就报错了,
解释原因:因为udp是面向报文的,每个消息是一个包,接收端设置接受大小的时候,必须要比你发的这个 包要大,不然一次接受不了就会报错,而tcp是不会报错的,这也是为什么udp会丢包的原因
打印进度条(简易)
import time
for i in range(20):
print('\r' + i*'*',end='')
time.sleep(0.2)
1.缓冲区
每个socket被创建以后,都会分配两个缓冲区,输入缓冲区和输出缓冲区,默认大小都是8k,可以通过getsocket()获取,暂时存放传输数据,防止程序在发送的时候卡阻,提高代码运行效率.
首先看python的系统交互subprocess:
import subprocess
sub_obj = subprocess.Popen(
'ls', #系统命令
shell = True, #固定格式
stdout=subprocess.PIPE, #标准输出 PIPE管道,保存着指令的执行结果
stderr=subprocess.PIPE #标准错误输出
)
print('正确输出',sub_obj.stdout.read().decode('gbk'))
print('错误输出',sub_obj.stderr.read().decode('gbk'))
#测试byte长度
# print(len(b'hello'))
# print(bytes(str(2),encoding='utf-8'))
结果编码是以但钱所在系统为准的,诺为windo,则用GBK解码,且只能从管道里读取一次结果
2.黏包现象

1.tcp两种黏包现象:
a. 发送端需要等缓冲区满了才发送出去,造成黏包(发送时间的间隔很短,数据也很小,会被底层优化算法河道一起,产生黏包现象)
server端的代码示例额如下:
from socket import *
ip_port = ('127.0.0.1',8080)
tcp_socket_server =socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen()
conn,addr = tcp_socket_server.accept()
#服务端连接接收两个信息
data1=conn.recv(10)
data2=conn.recv(10)
print('------>',data1.decode('utf-8'))
print('------>',data2.decode('utf-8'))
conn.close()
client端的实例如下:
import socket
BUFSIZE= 1024
ip_port = ('127.0.0.1',8080)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res = s.connect(ip_port)
s.send('hi'.encode('utf-8'))
s.send('meinv'.encode('utf-8'))
b. 接受方没有及时接受缓冲区的包,导致多个包接受,(客户端发送一段数据,服务端只收了一小部分,服务区 下次接受的时候还是从缓冲区拿上次遗留的数据,产生黏包)第一次如果发送的数据大小2000B,接受端一次性接受大小为1024,这样就导致剩下的内容会被下一次recv接收到,导致结果的错乱.
server端的代码示例额如下:
import socket
import subprocess
server = socket.socket()
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn, addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024)
print(from_client_cmd.decode('utf-8'))
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
std_msg = sub_obj.stdout.read()
print('指令的执行结果长度>>>>',len(std_msg))
conn.send(std_msg)
client端的实例如下:
import socket
client = socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
cmd = input("请输入指令:")
client.send(cmd.encode('utf-8'))
server_cmd_result = client.recv(1024)
print(server_cmd_result.decode('gbk'))
解决tcp黏包的方案有两种,第一种是了解一下,第二种是必须记住.
1.方案一:由于接受方不知道发送端将要传送的自接力的长度,导致接收的尾喉,可能接收不全,或者多接收另外一次发送的内容,把自己将要送的字节流总大小让对方知晓,然后接收方发一个确认消息给发送端,然后发送端在发送过来后面的真实数据,接收方在来呢接收完
server端的代码示例额如下:
import socket
import subprocess
server = socket.socket( )
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024)
print(from_client_cmd.decode('utf-8'))#接收到客户端发送来的系统指令,我服务端通过subprocess模块到服务端自己的系统里面执行这条指令
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE, #正确结果的存放的位置
stderr=subprocess.PIPE #错误结果的存放的位置
)
# 从管道里面拿结果,通过subprocess.Popen的实例化对象.stdout.read()方法来获取管道中的结果
std_msg = sub_obj.stdout.read()
#为了解决黏包现象,我们统计一下消息的长度,现将消息的长度发送给客户端,客户端通过这个长度来接收后面我们要发送的真实数据
std_msg_len = len(std_msg)
#首先将数据长度的数据类型装换成bytes类型
std_bytes_len = str(len(std_msg)).encode('utf-8')
print('指令的执行结果长度>>>>>:',len(std_msg))
conn.send(std_bytes_len)
status = conn.recv(1024)
if status.decode('utf-8') == 'ok':
conn.send(std_msg)
else:
pass
client端的实例如下:
import socket
client = socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
cmd = input('请输入指令:')
client.send(cmd.encode('utf-8'))
server_res_len = client.recv(1024).decode('utf-8')
print('来自服务端的消息长度',server_res_len)
client.send(b'ok')
server_cmd_result = client.recv(int(server_res_len))
print(server_cmd_result.decode('gbk'))`
2.方案二: 通过struck模块将需要发送的内容长度进行打包,打包成一个4字节长度的数据发送到对端,对端只要取出前4个字节,然后对前4个字节的数据进行捷豹,拿到发送的长度,然后通过这个长度来继续接受我们要发送的内容.
struck模块的使用:struck模块中最重的两个函数就是pack()打包,unpack()解包

pack(): 我们这里只介绍'i'这个int类型,上面的途中列举了处理可以打包的所有的数据类型,并且struck处理pack和unpack两个方法之外还有好多别的方法和用法.
import struct
num = 100
# num太大的话会报错,
# struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围
# 打包,将int类型的数据打包成4个长度的bytes类型的数据
byt = struct.pack('i',num)
print(byt)
# 解包,将bytes类型的数据,转换为对应的那个int类型的数据
# 注:unpack返回的是truple
int_num = struct.unpack('i',byt)[0]
print(int_num)
解决黏包现象的第二种方案:
服务端:
import socket
import subprocess
import struct
server = socket.socket()
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024)
print(from_client_cmd.decode('utf-8'))
#接收到客户端发送过来的系统指令,我服务端通过subprocess模块到服务端自己的系统里面执行这条指令
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE, #正确结果的存放位置
stderr=subprocess.PIPE #错误结果的存放位置
)
# 从管道里面拿出结果,通过subprocess.Popen的实例化对象.stdout.read()方法来获取管道中的结果
std_msg = sub_obj.stdout.read()
#为了解决黏包现象,我们统计了一下消息的长度,先将消息的长度发送给客户端,客户端通过这个长度来接收后面我们要发送的真实的数据
std_msg_len = len(std_msg)
print('指令的执行结果长度>>>>>>',len(std_msg))
msg_lenint_struct =struct.pack('i',std_msg_len)
conn.send(msg_lenint_struct+std_msg)
客户端:
import socket
import struct
client = socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
cmd = input('请输入指令:')
#发送指令
client.send(cmd.encode('utf-8'))
#接收数据长度,首先接收4个字节长度的数据,因为这个4个字节是长度
server_res_len=client.recv(4)
msg_len= struct.unpack('i',server_res_len)[0]
print('来自服务端的消息长度',msg_len)
#通过解包出来的长度,来接收后面的真实数据
server_cmd_result =client.recv(msg_len)
print(server_cmd_result.decode('gbk'))
查看自己的缓存的大小
# print(server.getsockopt(socket.SOL_SOCKET,socket.SO_SNDBUF))
# print(server.getsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF))
3. udp是面向包的,所以udp是不存在黏包的。
在udp代码中,我们在server端接受返回消息的时候,我们设置的recvfrom(1024),那么当我们输入的执行指令为'dir'的时候,若dir在当前文件夹下输出的内容大于1024,然后就报错了,
解释原因:因为udp是面向报文的,每个消息是一个包,接收端设置接受大小的时候,必须要比你发的这个 包要大,不然一次接受不了就会报错,而tcp是不会报错的,这也是为什么udp会丢包的原因
打印进度条(简易)
import time
for i in range(20):
print('\r' + i*'*',end='')
time.sleep(0.2)
- Python 黏包及黏包解决方案
粘包现象 说粘包之前,我们先说两个内容,1.缓冲区.2.windows下cmd窗口调用系统指令 1 缓冲区(下面粘包现象的图里面还有关于缓冲区的解释) 每个 socket 被创建后,都会分配两个缓冲区 ...
- 有关 Android Studio 重复引入包的问题和解决方案
虽然相同包名相同类名的文件在不同 SDK 中出现的概率极低,但是一旦出现,处理起来就比较棘手.最好的解决方案就是联系提供 SDK 的技术人员反映问题,让其通过修改源码重新打包一个新的 Jar 包. 还 ...
- Netty中粘包和拆包的解决方案
粘包和拆包是TCP网络编程中不可避免的,无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包和拆包 TCP是个“流”协议,所谓流,就是没有界限的一串 ...
- Flutter学习笔记(28)--使用第三方jar包
如需转载,请注明出处:Flutter学习笔记(28)--使用第三方jar包 1.打开一个Flutter项目,点击编码窗口右上角的Open for Editing in Android Studio,这 ...
- java nio消息半包、粘包解决方案
问题背景 NIO是面向缓冲区进行通信的,不是面向流的.我们都知道,既然是缓冲区,那它一定存在一个固定大小.这样一来通常会遇到两个问题: 消息粘包:当缓冲区足够大,由于网络不稳定种种原因,可能会有多条消 ...
- TCP 粘包 - 拆包问题及解决方案
目录 TCP粘包拆包问题 什么是粘包 - 拆包问题 为什么存在粘包 - 拆包问题 粘包 - 拆包 演示 粘包 - 拆包 解决方案 方式一: 固定缓冲区大小 方式二: 封装请求协议 方式三: 特殊字符结 ...
- TCP粘"包"问题浅析及解决方案Golang代码实现
一.粘"包"问题简介 在socket网络编程中,都是端到端通信,客户端端口+客户端IP+服务端端口+服务端IP+传输协议就组成一个可以唯一可以明确的标识一条连接.在TCP的sock ...
- 粘包处理现象及其解决方案——基于NewLife.Net网络库的管道式帧长粘包处理方法
[toc] #1.粘包现象 每个TCP 长连接都有自己的socket缓存buffer,默认大小是8K,可支持手动设置.粘包是TCP长连接中最常见的现象,如下图 socket缓存中有5帧(或者说5包)心 ...
- day34 基于TCP和UDP的套接字方法 粘包问题 丢包问题
TCP 基于流的协议 又叫可靠性传输协议 通过三次握手 四次挥手 来保证数据传输完毕 缺点效率低 正因为是基于流的协议 所以会出现粘包问题粘包问题:原因一:是应为数据是先发送给操作系统,在操作系统中有 ...
- 什么是"抓包"?怎样"抓包"?
你是网络管理员吗?你是不是有过这样的经历:在某一天的早上你突然发现网络性能急剧下降,网络服务不能正常提供,服务器访问速度极慢甚至不能访问,网络交换机端口指示灯疯狂地闪烁.网络出口处的路由器已经处于满负 ...
随机推荐
- SpringMVC学习(六)——@InitBinder注解
有些类型的数据是无法自动转换的,比如请求参数中包含时间类型的数据,无法自动映射到Controller里的Date参数.需要使用@initBinder注解为binder提供一个数据的转换器,这个转换器可 ...
- shiro(java安全框架)
shiro(java安全框架) 以下都是综合之前的人加上自己的一些小总结 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的A ...
- 使用intellij idea搭建MAVEN+SSM(Spring+SpringMVC+MyBatis)框架
基本概念 使用SSM(Spring,SpringMVC和Mybatis) 1.1.Spring Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod ...
- 【转】PBOC3.0和PBOC2.0标准规范异同分析
2013年2月,中国人民银行发布了<中国金融集成电路(IC)卡规范(V3.0)>(以下简称PBOC3.0),PBOC3.0是在中国人民银行2005年颁布的<中国金融集成电路(IC)卡 ...
- 重新认识KCP
什么是KCP KCP是一种网络传输协议(ARQ,自动重传请求),可以视它为TCP的代替品,但是它运行于用户空间,它不管底层的发送与接收,只是个纯算法实现可靠传输,它的特点是牺牲带宽来降低延迟.因为TC ...
- selenium借助send_keys实现上传(以网易邮箱为例)
#code:utf-8from selenium import webdriverimport time#网易163邮箱dr = webdriver.Firefox()file_path = 'htt ...
- SAP R/3系统的R和3分别代表什么含义,负载均衡的实现原理
1972年,SAP诞生,推出了RF系统(实时财务会计系统), 后来命名为R1. R指Real time.3既指第三代系统,又代表3层架构. 三层架构分别为下图的Presentation server ...
- Django 创建model的一些注意事项
自增主键字段¶ 默认情况下,Django 会给每个模型添加下面这个字段: id = models.AutoField(primary_key=True) 这是一个自增主键字段. 如果你想指定一个自定义 ...
- Git Brash在Windows下乱码问题
,/etc/gitconfig: [gui] encoding = utf- #代码库统一用urf-8,在git gui中可以正常显示中文 [i18n] commitencoding = GB2312 ...
- 【[HNOI2015]菜肴制作】
\(SDSC\)讲过的题,复习一下 如果用一个小根堆来维护拓扑的话显然是会不行的,因为这样求出来的是字典序最小的拓扑序,并不一定是1尽可能在前 因为字典序是贪心的,如果前面的一位能小就尽可能的小,并不 ...