zoukankan      html  css  js  c++  java
  • 缓冲区,粘包,解决粘包的方法,

    缓冲区:暂时存放传输数据的,防止你的程序在发送数据的时候卡主,提高代码运行效率

        输入缓冲区:recv

        输出缓冲区:send

        缓冲区有长度限制

    MTU最大传输单元,网络层限制是1500B,每次发送数据的时候最好不要超过这个数

    粘包

      粘包现象:

      1.连续发送小的数据,间隔时间很短,有可能一次就接受欧到了这几个连续的情节在一起的小数据,

      原因:未来提高tcp传输效率,内部提供了一个叫做Nagel算法,他的意思就是未来避免你连续发送小数据.

      2.当你一次接收的数据长度小于你一次发送的数据长度,那么一次接收完剩下的数据会在下一次接收数据的时候一起接收

      原因:面向流的传输

      粘包的根本原因:

        两端互相不知道对方发送数据的长度

      针对上面的原因有两种解决粘包的方法

      

        1在发送数据前,先发送数据的长度,name接收根据的长度来进行接收数据

     服务端:

        

    import socket
    import subprocess

    server = socket.socket()
    ip_port = ('192.168.15.113',8001)
    server.bind(ip_port)
    server.listen()
    conn,addr = server.accept()
    while 1:
    #来自客户端的指令
    print('等待接受信息。。。')
    from_client_cmd = conn.recv(1024).decode('utf-8')
    print(from_client_cmd)
    sub_obj = subprocess.Popen(
    from_client_cmd, #客户端的指令
    shell=True,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    )

    #接受到的返回信息是bytes类型的,并且windows系统的默认编码为gbk
    server_cmd_msg = sub_obj.stdout.read()
    # server_cmd_err = sub_obj.stderr.read().decode('gbk')
    cmd_msg_len = str(len(server_cmd_msg))
    print('指令返回的正确信息的长度>>>',cmd_msg_len)
    # print('指令返回的正确信息>>>',server_cmd_msg)
    # print('指令返回的错误信息...',server_cmd_err)

    conn.send(cmd_msg_len.encode('gbk'))

    from_client_ack = conn.recv(1024).decode('utf-8')
    print('from_client_ack',from_client_ack)
    if from_client_ack == 'ok':

    conn.send(server_cmd_msg)
    else:
    continue

        

     客户端:

        

    import socket
    client = socket.socket()
    server_ip_port = ('192.168.15.113',8001)
    client.connect(server_ip_port)
    while 1:
    msg = input('请输入要执行的指令>>>')
    client.send(msg.encode('utf-8'))
    #先接收服务端要发送给我的信息的长度
    from_server_msglen = int(client.recv(1024).decode('gbk'))
    print('..........',from_server_msglen)
    #给服务端回应一个收到了你的信息长度的确认信息
    client.send('ok'.encode('utf-8'))

    #拿到信息长度后,将信息长度作为参数给了recv,recv就按照这个长度大小来接受服务端后面要给我发送的数据
    from_server_stdout = client.recv(from_server_msglen).decode('gbk')

    print('收到的正确信息:', from_server_stdout)

    # from_server_error = client.recv(1024).decode('utf-8')
    # print('收到的错误信息:',from_server_error)

    2. 把要发送的数据打成包的形式直接传输

    服务端:

      

    import socket
    import subprocess
    import struct

    server = socket.socket()
    ip_port = ('192.168.15.113',8001)
    server.bind(ip_port)
    server.listen()
    conn,addr = server.accept()
    while 1:
    #来自客户端的指令
    print('等待接受信息。。。')
    from_client_cmd = conn.recv(1024).decode('utf-8')
    print(from_client_cmd)
    #通过subprocess模块执行服务端的系统指令,并且拿到指令执行结果
    sub_obj = subprocess.Popen(
    from_client_cmd, #客户端的指令
    shell=True,
    stdout=subprocess.PIPE, #标准输出:正确指令的执行结果在这里
    stderr=subprocess.PIPE, #标准错误输出:错误指令的执行结果在这里
    )
    #接受到的返回信息是bytes类型的,并且windows系统的默认编码为gbk
    server_cmd_msg = sub_obj.stdout.read()
    # server_cmd_err = sub_obj.stderr.read().decode('gbk')
    #首先计算出你将要发送的数据的长度
    cmd_msg_len = len(server_cmd_msg)
    #先对数据长度进行打包,打包成4个字节的数据,目的是为了和你将要发送的数据拼在一起,就好我们自定制了一个消息头
    msg_len_stru = struct.pack('i',cmd_msg_len)
    conn.send(msg_len_stru) #首先发送打包成功后的那4个字节的数据
    conn.sendall(server_cmd_msg) #循环send数据,直到数据全部发送成功

      

    客户端: 

        

    import socket
    import struct
    client = socket.socket()
    server_ip_port = ('192.168.15.113',8001)
    client.connect(server_ip_port)
    while 1:
    msg = input('请输入要执行的指令>>>')
    client.send(msg.encode('utf-8'))
    #先接收服务端要发送给我的信息的长度,前4个字节,固定的
    from_server_msglen = client.recv(4)
    unpack_len_msg = struct.unpack('i',from_server_msglen)[0]
    #接收数据长度统计,和服务端发给我的数据长度作比较,来确定跳出循环的条件
    recv_msg_len = 0
    #统计拼接接收到的数据,注意:这个不是统计长度
    all_msg = b''
    while recv_msg_len < unpack_len_msg:
    every_recv_data = client.recv(1024)
    #将每次接收的数据进行拼接和统计
    all_msg += every_recv_data
    #对每次接收到的数据的长度进行累加
    recv_msg_len += len(every_recv_data)

    print(all_msg.decode('gbk'))


      
  • 相关阅读:
    [Swift]LeetCode910. 最小差值 II | Smallest Range II
    转 关于shell脚本中#!/bin/bash and #!/bin/ksh 的说明
    转 对象继承
    转 PHP编程过程中需要了解的this,self,parent的区别
    转: ORA-06508 could not find program unit being called: "DBSNMP.BSLN_INTERNAL
    Multitenant best Practice clone pdb seed and Clone a Pluggable Database – 12c Edition
    Plugging an Unplugged Pluggable Database issue 3
    日历 php
    Datapatch AND What to do if the status of a datapatch action was not SUCCESS due to finding non-ignorable errors
    oracle中的用户详解 【转】
  • 原文地址:https://www.cnblogs.com/lilei1996/p/9811694.html
Copyright © 2011-2022 走看看