zoukankan      html  css  js  c++  java
  • python网络编程-socket“粘包”(小数据发送问题)

    一:什么是粘包

      “粘包”, 即服务器端你调用时send 2次,但你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区里,等缓冲区满了、或者数据等待超时了,数据才会被send到客户端,这样就把好几次的小数据拼成一个大数据,统一发送到客户端了,这么做的目地是为了提高io利用效率,一次性发送总比连发好几次效率高嘛。 但也带来一个问题,就是“粘包”,即2次或多次的数据粘在了一起统一发送了。这里必须要想办法把粘包分开, 因为不分开,你就没办法取出来服务器端返回的命令执行结果的大小。

      1)time.sleep(0.5),经多次测试,让服务器程序sleep 至少0.5就会造成缓冲区超时。

      2)不用sleep,服务器端每发送一个数据给客户端,就立刻等待客户端进行回应,即调用 conn.recv(1024), 由于recv在接收不到数据时是阻塞的,这样就会造成,服务器端接收不到客户端的响应,就不会执行后面的conn.sendall(命令结果)的指令,收到客户端响应后,再发送命令结果时,缓冲区就已经被清空了,因为上一次的数据已经被强制发到客户端了。

    #_*_coding:utf-8_*_
    
    
    
    import socket
    import os,subprocess
    
    
    server = socket.socket() #获得socket实例
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
    server.bind(("localhost",9999)) #绑定ip port
    server.listen()  #开始监听
    
    while True: #第一层loop
        print("等待客户端的连接...")
        conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
        print("新连接:",addr )
        while True:
    
            data = conn.recv(1024)
            if not data:
                print("客户端断开了...")
                break #这里断开就会再次回到第一次外层的loop
            print("收到命令:",data)
            #res = os.popen(data.decode()).read() #py3 里socket发送的只有bytes,os.popen又只能接受str,所以要decode一下
            res = subprocess.Popen(data,shell=True,stdout=subprocess.PIPE).stdout.read() #跟上面那条命令的效果是一样的
            if len(res) == 0:
                res = "cmd exec success,has not output!".encode("utf-8")
            conn.send(str(len(res)).encode("utf-8")) #发送数据之前,先告诉客户端要发多少数据给它
            print("等待客户ack应答...")
            client_final_ack = conn.recv(1024) #等待客户端响应
            print("客户应答:",client_final_ack.decode())
            print(type(res))
            conn.sendall(res) #发送端也有最大数据量限制,所以这里用sendall,相当于重复循环调用conn.send,直至数据发送完毕
    
    server.close()
    
    接收大数据 server端

      

    #_*_coding:utf-8_*_
    
    
    import socket
    import sys
    
    client = socket.socket()
    
    client.connect(("localhost",9999))
    
    while True:
        msg = input(">>:").strip()
        if len(msg) == 0:continue
        client.send( msg.encode("utf-8") )
    
        res_return_size  = client.recv(1024) #接收这条命令执行结果的大小
        print("getting cmd result , ", res_return_size)
        total_rece_size = int(res_return_size)
        print("total size:",res_return_size)
        client.send("准备好接收了,发吧loser".encode("utf-8"))
        received_size = 0 #已接收到的数据
        cmd_res = b''
        f = open("test_copy.html","wb")#把接收到的结果存下来,一会看看收到的数据 对不对
        while received_size != total_rece_size: #代表还没收完
            data = client.recv(1024)
            received_size += len(data) #为什么不是直接1024,还判断len干嘛,注意,实际收到的data有可能比1024少
            cmd_res += data
        else:
            print("数据收完了",received_size)
            #print(cmd_res.decode())
            f.write(cmd_res) #把接收到的结果存下来,一会看看收到的数据 对不对
        #print(data.decode()) #命令执行结果
    
    client.close()
    
    接收大数据客户端
  • 相关阅读:
    MyBatis学习总结(三)——优化MyBatis配置文件中的配置
    MyBatis学习总结(一)——MyBatis快速入门
    java基础学习总结——java环境变量配置
    java基础学习总结——开篇
    java基础学习总结——基础语法1
    java基础学习总结——基础语法2
    java基础学习总结——面向对象1
    java基础学习总结——异常处理
    Linux网络配置(setup)
    Linux搭建Apache+Tomcat实现负载均衡
  • 原文地址:https://www.cnblogs.com/lixiang1013/p/7019833.html
Copyright © 2011-2022 走看看