• socket套接字 tcp协议下的粘包处理


    socket套接字初识:

    服务端: import socket server = socket.socket() #买手机 server.bind(('127.0.0.1', 11090)) #插手机卡 bind(IP,PORT) #127.0.0.1:本地回环地址,只能本机访问 server.listen(5) #开机,半连接池 conn, addr = server.accept() #待机等待接电话 三次握手完成 data=conn.recv(1024) #接听别人电话,只接收1024个字节 bytes print(data) conn.send(b'hello wrold!') #跟别人说话 conn.close() #关闭通信连接 server.close()#关闭服务器 客户端: import socket client = socket.socket() #不传参数默认为TCP协议 client.connect(('127.0.0.1', 11090)) #找服务器 client.send(b'hello') data = client.recv(1024) print(data) client.close()

      

    struct的简单使用
    
    import struct
    data='123456'
    data=struct.pack('i', len(data))
    print(len(data)) #4
    ret=struct.unpack('i', data)[0]
    print(ret)      #6
    

      

    subprocess 与 tasklist 的配合使用
    
    import subprocess
    
    obj = subprocess.Popen('tasklist',
                           shell=True,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE)
    stdout = obj.stdout.read()
    print('stdout',stdout.decode('gbk'))
    stderr = obj.stderr.read()
    print('stderr',stderr.decode('gbk'))
    

      

    解决粘包的方法:
    
    
    服务端:
    import socket
    import struct
    import json
    import subprocess
    
    
    server = socket.socket()
    server.bind(('127.0.0.1', 8090))
    server.listen(5)
    while True:
        conn,addr = server.accept()
        while True:
            try:
                data = conn.recv(1024).decode('utf-8')
                # if len(data) == 0:break
                obj = subprocess.Popen(data,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                stdout = obj.stdout.read()
                stderr = obj.stderr.read()
                print(len(stdout+stderr))   #打印真实数据长度
    
                head_dic={
                    'filename':'cls.av',
                    'len':len(stdout+stderr)
                }
    
                header_bytes=json.dumps(head_dic).encode('utf-8')
                #制作报头
                header=struct.pack('i', len(head_dic))  #打包为4个字节       此处len()括号里应该为len(header_bytes)
                conn.send(header)  #先发报头
                conn.send(header_bytes) #再发字典
                conn.send(stderr+stdout) #最后发真实数据        #此处的stdout与stderr均是字节类型
            except ConnectionResetError:
                break
        conn.close()
    
    
    
    客户端:
    import json
    import socket
    import struct
    
    
    client = socket.socket()
    client.connect(('127.0.0.1',8090))
    
    while True:
        msg = input('>>>:').encode('utf-8')  #字符串编码为字节
        if len(msg) == 0: continue
        client.send(msg)   #发送原始数据
        header = client.recv(4) #接收4个长度的报头
        head_len = struct.unpack('i', header)[0]  #解压拿到字典数据长度
        head_dic = json.loads(client.recv(head_len).decode('utf-8'))
        #接收字典里真实长度的字节解码后反序列化的所有信息
        print(head_dic)
        #对需要接收的数据,进行循环接收
        total_size = head_dic['len']  #所需要数据的真实长度
        recv_size = 0
        res = b'' #用来保存所接收的数据
        while recv_size < total_size:
            data = client.recv(1024) #开始接收真实数据,一次最多1024字节
            res += data
            recv_size += len(data)  #记录所接收的数据的长度
        print(res.decode('gbk'))  #将字节类型解码为gbk格式下的字符串
    
    
    #逻辑正确,可是会报错              问题已解决:彼此间发送接收的数据应该为字节
    #json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 2 (char 1)
    

      

    上述程序的修订版:
    
    #服务端
    
    import socket
    import struct
    import json
    import subprocess
    
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    while True:
        conn, addr = server.accept()
        while True:
            try:
                data = conn.recv(1024).decode('utf-8')
                obj = subprocess.Popen(data,
                                       shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE)
                stdout = obj.stdout.read()  #标准输出流
                stderr = obj.stderr.read()  #标准错误流
                print(len(stdout+stderr))
                print('看一下类型',type(stdout))  #<class 'bytes'>
                head_dic = {'filename':'text.py',
                            'len':len(stdout+stderr)}
                #将字典装换为json类型的字节
                header_bytes = json.dumps(head_dic).encode('utf-8')
                #制作报头:
                header = struct.pack('i', len(header_bytes))
                #发送报头
                conn.send(header)
                #发送字典
                conn.send(header_bytes)
    
                '''
                #制作报头
                header = struct.pack('i',len(head_dic))
                #发送报头
                conn.send(header)  #发送的数据应该为字节模式
                #再发字典
                conn.send(json.dumps(head_dic).encode('utf-8'))
                '''
                #最后发真实数据
                # conn.send((stdout+stderr).encode('utf-8'))
                #stdout本身就是字节类型,因此不需要转码
                conn.send(stdout+stderr)
            except ConnectionResetError:
                break
        conn.close()
    
    
    #客户端:
    
    
    import socket
    import json
    import struct
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    while True:
        msg = input('>>>:').strip()
        if len(msg) ==0:continue
        client.send(msg.encode('utf-8'))
        #接收报头
        header = client.recv(4)
        #解包报头,获取字典长度
        head_len = struct.unpack('i',header)[0]
        #接收字典
        header_dic = client.recv(head_len)
        #拿到字典里的信息
        header_dic = json.loads(header_dic.decode('utf-8'))
        print(header_dic)
        #对需要接受的真实数据,进行循环接收
        total_size = header_dic.get('len')
        recv_size = 0
        res = b''
        while recv_size < total_size:
            data = client.recv(1024)
            res += data
            recv_size += len(data)
        print(res.decode('gbk'))  #此处需要转码为gbk
    

      

    知识点总结:
    1、 TCP协议(流式协议,可靠协议,会出现粘包)
                       会将数据量比较小的且时间间隔比较短的数据一次性打包发送给接收端
    
           UDP协议(数据报协议):
                        不需要建立双向连接,但是传输数据不可靠,可能会存在丢包情况。通信速度快,但是发送的数据不会再内存里保留。
    
    
    2、socket套接字
        基于socket实现客户端与服务端通信,处在应用层与传输层之间
    
    3、本机回环地址: 127.0.0.1  只能本机访问
    
    4、解决粘包问题的方法:
        
        服务端:
                    1、先发报头
                    2、再发字典
                    3、再发所需要的真实数据
    
        客户端:
                    1、先接受4个长度的报头
                    2、解包拿到字典的数据长度
                    3、接受字典,需要反序列化,获取字典里所有的信息
                    4、接受真实数据
    

      

  • 相关阅读:
    How can i use iptables on centos 7?
    Running Jenkins behind Nginx
    GPG入门教程
    HTML5 canvas标签-4 灰度直方图的实现
    [转载]手把手用C++解密Chrome80版本数据库
    Delphi
    7-zip Delphi API
    cef对本地web资源打包加密
    CEF3资源重定向、读取加密资源、读取zip资源
    axios设置withCredentials导致“跨域”的解决方案
  • 原文地址:https://www.cnblogs.com/changwenjun-666/p/10810446.html
Copyright © 2020-2023  润新知