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)
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)

day 28 黏包及黏包解决方案的更多相关文章

  1. Python 黏包及黏包解决方案

    粘包现象 说粘包之前,我们先说两个内容,1.缓冲区.2.windows下cmd窗口调用系统指令 1 缓冲区(下面粘包现象的图里面还有关于缓冲区的解释) 每个 socket 被创建后,都会分配两个缓冲区 ...

  2. 有关 Android Studio 重复引入包的问题和解决方案

    虽然相同包名相同类名的文件在不同 SDK 中出现的概率极低,但是一旦出现,处理起来就比较棘手.最好的解决方案就是联系提供 SDK 的技术人员反映问题,让其通过修改源码重新打包一个新的 Jar 包. 还 ...

  3. Netty中粘包和拆包的解决方案

    粘包和拆包是TCP网络编程中不可避免的,无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包和拆包 TCP是个“流”协议,所谓流,就是没有界限的一串 ...

  4. Flutter学习笔记(28)--使用第三方jar包

    如需转载,请注明出处:Flutter学习笔记(28)--使用第三方jar包 1.打开一个Flutter项目,点击编码窗口右上角的Open for Editing in Android Studio,这 ...

  5. java nio消息半包、粘包解决方案

    问题背景 NIO是面向缓冲区进行通信的,不是面向流的.我们都知道,既然是缓冲区,那它一定存在一个固定大小.这样一来通常会遇到两个问题: 消息粘包:当缓冲区足够大,由于网络不稳定种种原因,可能会有多条消 ...

  6. TCP 粘包 - 拆包问题及解决方案

    目录 TCP粘包拆包问题 什么是粘包 - 拆包问题 为什么存在粘包 - 拆包问题 粘包 - 拆包 演示 粘包 - 拆包 解决方案 方式一: 固定缓冲区大小 方式二: 封装请求协议 方式三: 特殊字符结 ...

  7. TCP粘"包"问题浅析及解决方案Golang代码实现

    一.粘"包"问题简介 在socket网络编程中,都是端到端通信,客户端端口+客户端IP+服务端端口+服务端IP+传输协议就组成一个可以唯一可以明确的标识一条连接.在TCP的sock ...

  8. 粘包处理现象及其解决方案——基于NewLife.Net网络库的管道式帧长粘包处理方法

    [toc] #1.粘包现象 每个TCP 长连接都有自己的socket缓存buffer,默认大小是8K,可支持手动设置.粘包是TCP长连接中最常见的现象,如下图 socket缓存中有5帧(或者说5包)心 ...

  9. day34 基于TCP和UDP的套接字方法 粘包问题 丢包问题

    TCP 基于流的协议 又叫可靠性传输协议 通过三次握手 四次挥手 来保证数据传输完毕 缺点效率低 正因为是基于流的协议 所以会出现粘包问题粘包问题:原因一:是应为数据是先发送给操作系统,在操作系统中有 ...

  10. 什么是"抓包"?怎样"抓包"?

    你是网络管理员吗?你是不是有过这样的经历:在某一天的早上你突然发现网络性能急剧下降,网络服务不能正常提供,服务器访问速度极慢甚至不能访问,网络交换机端口指示灯疯狂地闪烁.网络出口处的路由器已经处于满负 ...

随机推荐

  1. c#编程指南(五) 扩展方法(Extension Method)

    C# 3.0就引入的新特性,扩展方法可以很大的增加你代码的优美度,扩展方法提供你扩展.NET Framewoke类的扩展途径,书写和规则也简单的要命. 编写扩展方法有下面几个要求: 第一:扩展方法所在 ...

  2. 证书制作 z

    一.WCF中的安全方式 说到安全就会涉及到认证,消息一致性和机密性,WCF的安全方式分为两种,即传输安全和消息安全. 传输安全和消息安全的区别:传输安全提供点对点的安全: 比如 A 提供服务,B和C直 ...

  3. 【Leetcode】【Medium】3Sum

    Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all un ...

  4. 如何使用Adobe Reader复制PDF文档上的文字

    PDF文档大家常用,但是有没有简单的方法能够提取PDF文档上的文字,然后使用呢?除了将PDF转换成Word,这里介绍一种更为简单实用的方法复制PDF文本文字,Adobe Reader是大家都常用的PD ...

  5. JavaScript函数的声明与调用方式

    入职第一天小记 对于初入前端的程序猿来说,对于函数的理解与使用可谓是相当浅薄的,回顾这自己近几年的工作以及学习经历,准备对JavaScript来个系统的总结. 如果要我们对H5中的表单做个简单的校验, ...

  6. python数据结构(整理)

    http://www.cnblogs.com/yupeng/p/3413763.html 1. 单链表 链表的定义: 链表(linked list)是由一组被称为结点的数据元素组成的数据结构,每个结点 ...

  7. 150行JavaScript代码实现增强现实

    增强现实技术(Augmented Reality,简称 AR),是一种实时地计算摄影机影像的位置及角度并加上相应图像.视频.3D模型的技术,这种技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动.这 ...

  8. NPM cache相关

    今天下午把package.lock.json用别人的替换了,然后编译一堆报错,这个问题弄了一下午. 总结一下经验: 1.关于npm cache NPM会把所有下载的包保存,放在用户文件夹下面,在我的w ...

  9. [原]零基础学习在Android进行SDL开发后记

    本着学习交流记录的目的编写了这个系列文章,主要用来记录如何从零开始学习SDL开发的过程,在这个过程中遇到了很多问题,差点就放弃了.首先是SDL的Android移植的时候遇到了比较坑的是SDL移植到An ...

  10. Spring Framework5.0 学习(1)—— 用Gradle构建一个Java Project

    1.0  安装Gradle,参考之前文章<Gradle入门实战(Windows版)> 2.0  使用gradle 快速生成一个Java project gradle init --type ...