zoukankan      html  css  js  c++  java
  • 解决socket粘包的两种low版模式 os.popen()和struct模块

    无注释版

    os.popen()模式

    server端

    import socket
    import os
    
    phone = socket.socket()
    phone.bind(("localhost",8088))
    phone.listen()
    
    while 1:
        conn,addr = phone.accept()
        while 1:
            try:
                from_client_data = conn.recv(1024)
                if from_client_data.upper() == b'Q':
                    print("客户端退出")
                    break
                print(from_client_data.decode('utf-8'))
                cmd_res = os.popen(from_client_data.decode("utf-8")).read()
                if len(cmd_res) == 0:
                    cmd_res = "cmd hs no output..."
                print(len(cmd_res.encode('gbk')))
                conn.send(str(len(cmd_res.encode('gbk'))).encode('gbk'))
                client.ack = conn.recv(1024)
                conn.send(cmd_res.encode('gbk'))
            except ConnectionResetError:
                break
        conn.close()
    phone.close()
    

    client端

    import socket
    phone = socket.socket()
    phone.connect(('localhost',8088))
    while 1:
        client_data = input(">>>")
        if not client_data:
            print("发送的内容不能为空")
            continue
        phone.send(client_data.encode("utf-8"))
        if client_data.upper() == "Q":
            quit()
        else:
            server_data = phone.recv(1024)
            phone.send("准备好接收了".encode('utf-8'))
            total_size = int(server_data.decode('gbk'))
            total_data = b''
            while 1:
                if len(total_data) < total_size:
                    total_data += phone.recv(1024)
                    print(len(total_data))
                else:
                    break
            print(total_data.decode('gbk'))
    phone.close()
    

    struct模块解决粘包

    server端

    import socket
    import subprocess
    import struct
    
    phone = socket.socket()
    phone.bind(("localhost",8088))
    phone.listen(5)
    
    while 1:
        conn,addr = phone.accept()
        print(addr)
        while 1:
            try:
                from_client_data = conn.recv(1024)
                if from_client_data.upper() == b'Q':
                    print("客户端退出")
                    break
                print(from_client_data.decode('utf-8'))
                obj = subprocess.Popen(from_client_data.decode('utf-8'),
                                       shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,)
                ret = obj.stdout.read()+obj.stderr.read()
                total_size = len(ret)
                header = struct.pack('i',total_size)
                print(total_size)
                conn.send(header)
                conn.send(ret)
            except ConnectionResetError:
                break
        conn.close()
    phone.close()
    

    client端

    import socket
    import struct
    phone = socket.socket()
    phone.connect(('localhost',8088))
    while 1:
        client_data = input(">>>")
        if not client_data:
            print("发送的内容不能为空")
            continue
        phone.send(client_data.encode("utf-8"))
        if client_data.upper() == "Q":
            quit()
        else:
            server_data = phone.recv(4)
            total_size = struct.unpack('i',server_data)[0]
            total_data = b''
            while 1:
                if len(total_data) < total_size:
                    total_data += phone.recv(1024)
                    print(len(total_data))
                else:
                    break
            print(total_data.decode('gbk'))
            # print(int(server_data.decode('gbk')))
    phone.close()
    
    

    有注释版

    os.popen()模式

    server端

    import socket
    import os
    
    phone = socket.socket() 
    
    # 实例化一个socket对象
    
    phone.bind(("localhost",8088)) 
    
    # 绑定地址(host,port)到套接字,在AF_INET下,以元组(host,port)的形式表示地址
    
    phone.listen(5) 
    
    #  	开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。
    
    while 1: # 开启循环,多个用户同时连接(当然不是并发,排队连接)
        conn,addr = phone.accept()
        
        # 被动接受TCP客户端连接,(阻塞式)等待连接的到来,会有两个值,conn我也不明白是什么值,addr是客户端连接的地址
        
        while 1: # 客户端与服务端多次对话,客户端多次执行循环
            try: # 异常处理,客户端直接退出ConnectionResetError错误
                from_client_data = conn.recv(1024) # 接收客户端数据
                if from_client_data.upper() == b'Q': 
                    # 判断客户端输入是否是q或Q,如果是q,直接退出当前连接
                    print("客户端退出")
                    break
                print(from_client_data.decode('utf-8')) # 输出客户端转码后的数据
                cmd_res = os.popen(from_client_data.decode("utf-8")).read() # 执行os命令,通过popen执行cmd命令
                if len(cmd_res) == 0: # 如果没有该命令,返回下面结果
                    cmd_res = "cmd hs no output..."
                conn.send(str(len(cmd_res.encode('gbk'))).encode('gbk')) # 发送数据,首先计算cmd_res的gbk字节长度,然后转换成字符串发送给客户端,因为int型不能发送
                print(len(cmd_res.encode('gbk'))) # 输出该命令返回的长度
                conn.send(cmd_res.encode('gbk')) # 执行一个接收,截断上下两个的粘包
                conn.send(cmd_res.encode('gbk')) # 发送给客户端
            except ConnectionResetError:
                break
        conn.close() # 关闭连接
    phone.close() # 关闭连接
    

    client端

    import socket
    phone = socket.socket() # 实例化对象
    phone.connect(('localhost',8088)) # 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
    while 1: # 循环输入
        client_data = input(">>>")
        if not client_data: # 如果输入为空,not client_data 则为True
            print("发送的内容不能为空")
            continue
        phone.send(client_data.encode("utf-8")) # 给服务端发送信息
        if client_data.upper() == "Q": # q退出
            quit()
        else:
            server_data = phone.recv(1024) # 接收返回的字节长度
            phone.send("准备好接收了".encode('utf-8')) # 给服务端发送消息,阻塞服务端上下造成粘包的问题(low版)
            total_size = int(server_data.decode('gbk')) # 接收到的是字符串,转换成整型
            total_data = b'' # 刚开始设置为0,空字符串则为0,前面加b表示字节
            while 1: # 如果我收到的字节小于total_size,则一直循环
                if len(total_data) < total_size:
                    total_data += phone.recv(1024) # 每次把信息加到total_data中
                    print(len(total_data))
                else:
                    break
            print(total_data.decode('gbk')) # 输出返回的结果
    phone.close() # 关闭连接
    

    struct模块解决粘包

    server端

    import socket
    import subprocess
    import struct
    
    phone = socket.socket() # 实例化一个socket对象
    phone.bind(("localhost",8088))
    # 绑定地址(host,port)到套接字,在AF_INET下,以元组(host,port)的形式表示地址
    phone.listen(5)
    #  	开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。
    
    while 1:# 开启循环,多个用户同时连接(当然不是并发,排队连接)
        
        conn,addr = phone.accept()
        
        # 被动接受TCP客户端连接,(阻塞式)等待连接的到来,会有两个值,conn我也不明白是什么值,addr是客户端连接的地址
        print(addr)
        while 1: # 客户端与服务端多次对话,客户端多次执行循环
            try: # 异常处理,客户端直接退出ConnectionResetError错误
                from_client_data = conn.recv(1024) # 接收客户端数据
                if from_client_data.upper() == b'Q': # 判断客户端输入是否是q或Q,如果是q,直接退出当前连接
                    print("客户端退出")
                    break
                print(from_client_data.decode('utf-8'))  # 输出客户端转码后的数据
                obj = subprocess.Popen(from_client_data.decode('utf-8'),
                                       shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,)
                # subprocess 模块中的代码
                # shell: 命令解释器,相当于调用cmd 执行指定的命令。
    		   # stdout:正确结果丢到管道中。
    		   # stderr:错了丢到另一个管道中。
    		   # windows操作系统的默认编码是gbk编码。
                ret = obj.stdout.read()+obj.stderr.read() # 加的是字节
                # 正确的输出跟错误的输出加起来,因为正确输出时,错误输出为空,所以加起来相当于0+1,没什么区别
                total_size = len(ret) # 计算返回命令的长度
                header = struct.pack('i',total_size) # 将一个数字转化成等长度的bytes类型。
                print(total_size) # 打印出返回命令的长度
                conn.send(header) # 发送固定长度的报头
                conn.send(ret) # 给客户端发送返回命令的结果
            except ConnectionResetError: 
                break
        conn.close() # 关闭连接
    phone.close() # 关闭连接
    

    client端

    import socket 
    import struct
    phone = socket.socket() # 实例化对象
    phone.connect(('localhost',8088)) # 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
    while 1: # 循环输入
        client_data = input(">>>")
        if not client_data: # 如果输入为空,not client_data 则为True
            print("发送的内容不能为空")
            continue
        phone.send(client_data.encode("utf-8")) # 给服务端发送信息
        if client_data.upper() == "Q": # q退出
            quit()
        else:
            server_data = phone.recv(4) # 接收报头长度
            total_size = struct.unpack('i',server_data)[0] # 反解报头
            total_data = b''  # 刚开始设置为0,空字符串则为0,前面加b表示字节
            while 1: # 如果我收到的字节小于total_size,则一直循环
                if len(total_data) < total_size: 
                    total_data += phone.recv(1024)  # 每次把信息加到total_data中
                    print(len(total_data))
                else:
                    break
            print(total_data.decode('gbk')) # 输出返回的结果,windows默认gbk
            # print(int(server_data.decode('gbk')))
    phone.close() # 关闭连接
    
  • 相关阅读:
    批处理集锦——(2)自定义函数
    批处理集锦——(1)怎么输出空行
    批处理实例——批量修改电视剧文件名称
    error C3861: “LOG4CPLUS_DEBUG”: 找不到标识
    vc个版本对应的vs版本
    Yii2中系统定义的常用路径别名,如果获取web的url
    asp提取声母源码
    Windows Error Code(windows错误代码详解)
    VS2013编译经常卡在正在从以下位置加载xxx.dll的符号
    Python3字符串截取值
  • 原文地址:https://www.cnblogs.com/alex3174/p/11360954.html
Copyright © 2011-2022 走看看