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. 关于ios 10 的新的部分

    编译器Xcode 8.2.1  SDK 10.2 1.   关于麦克风,相机,相册等部分的权限,需要在info.plist内进行设置,否则会出现crash.

  2. coder/programmer engineer Chirf Technology Offcer

    大概是某个C轮融资的医疗网站CTO被离职.而CTO是一个知乎大V和微信大号.此事一出,在微信群有支持也有反对之声.支持此CTO被离职的认为其在工作时没有Review程序,自己不写代码,而是热衷出没于技 ...

  3. July 19th 2017 Week 29th Wednesday

    Rather than envy others, it is better to speed up their own pace. 与其羡慕他人,不如加快自己的脚步. The envy of othe ...

  4. 一个asp.net小项目总结

    写这篇文章之前先吐槽一下,最近换了一个公司,是给一个国企做外包,有两个月了,感觉这里的气氛有点不爽,还有点怀念以前的公司.具体听我说来,这里有几个团队,.net,java,手机开发,.net只有6个人 ...

  5. java 开发常用IDE

    1.IntelliJ IDEA 2.eclipse 3.netbeans 这三个IDE都不错,据说IntelliJ IDEA最好,主要还是看个人喜好和需要.

  6. hdu-1792 A New Change Problem---数论&剩余系

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1792 题目大意: 给定A和B,A和B互质,求最大不能组合数,和不能组合数的个数. 解题思路: 由于g ...

  7. Django 创建模型 激活模型 简单的使用模型

    创建模型: 在你的开发环境中,已经有一个“项目” —— 已经建立起来,你将开始在上面做一些东西. 你编写的每个Django应用都是一个遵循特定约定的Python包. Django自带一个工具,它可以自 ...

  8. hdu1113 Word Amalgamation(详解--map和string的运用)

    版权声明:本文为博主原创文章.未经博主同意不得转载. vasttian https://blog.csdn.net/u012860063/article/details/35338617 转载请注明出 ...

  9. BZOJ2427:[HAOI2010]软件安装(树形DP,强连通分量)

    Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...

  10. 1.springboot:入门项目

    简介: Springboot 来简化spring应用开发,约定大于配置,去繁从简,just run 就可以创建一个独立的,产品应用 背景: J2EE笨重开发,繁多的配置,低下的开发效率,复杂的部署流程 ...