zoukankan      html  css  js  c++  java
  • 粘包问题以及解决方法

    subprocess模块

    1.可以帮你通过代码执行操作系统的终端命令

    2.并返回终端执行命令后的结果

    注意:stdout一定要在stderr前面

    import subprocess
    
    cmd=input('cmd>>>:')
    
    obj=subprocess.Popen(
        cmd,shell=True,
        stdout=subprocess.PIPE,#返回正确结果参数
        stderr=subprocess.PIPE#返回错误结果参数
    )
    
    result=obj.stdout.read()+obj.stderr.read()
    print(result.decode('gbk'))
    

    粘包问题

    服务端第一次发送的数据,客户端无法精确一次性接受完毕。下一次发送的数据与上一次数据粘在一起了。

    1.无法预测对方需要接受的数据大小长度

    2.多次连续发送数据量小,并且时间间隔短的数据一次性打包发送

    TCP协议特性:

    ​ tcp是一个流式协议,会将多次连续发送数据量小,并且时间间隔短的数据一次性打包发送

    解决粘包问题

    struct模块

    是一个可以将很长的数据长度,压缩成固定的长度的一个标记(数据报头)。

    必须先定义报头,发送报头,再发送真实数据

    即想发送文件,又想发送文件的描述信息

    '''
    -struct模块:
        是一个可以将很长的数据的长度,压缩成固定的长度的一个标记(数据报头)
    '''
    import struct
    #打包压缩
    # i模式,会将数据长度压缩成4个bytes
    str1='nihaoyanihaoyanihaoya'
    
    # 报头
    
    headers=struct.pack('i', len(str1))
    
    data_len=struct.unpack('i',headers)
    print(data_len)#(21,)
    print(data_len[0])#21
    

    解决粘包问题

    #服务端
    import socket
    import subprocess
    import struct
    
    server=socket.socket()
    
    server.bind(('127.0.0.1',9527))
    
    server.listen(5)
    
    while True:
        conn,addr=server.accept()
        while True:
            try:
    
                cmd=conn.recv(1024).decode('utf-8')
                if cmd=='q':
                    break
    
                if len(cmd)==0:
                    continue
    
                print(cmd)
                # 执行cmd命令
                obj=subprocess.Popen(cmd,shell=True,
                                     stderr=subprocess.PIPE,
                                     stdout=subprocess.PIPE,)
                #接受终端返回的数据
                result=obj.stdout.read()+obj.stderr.read()
                #打包压缩,获取报头
                headers=struct.pack('i',len(result))
                #发送报头
                conn.send(headers)
                #发送真实数据
                conn.send(result)
            except Exception as e:
                print(e)
                break
        conn.close()
    
    #客户端
    import socket
    import struct
    
    client=socket.socket()
    
    client.connect(('127.0.0.1',9527))
    
    while True:
        cmd=input('>>>:')
    
        client.send(cmd.encode('utf-8'))
    
        if cmd=='q':
            break
        #获取数据报头
        headers=client.recv(4)
        #解包,获取真实数据长度
        data_len=struct.unpack('i',headers)
        #获取真实数据
        data=client.recv(data_len[0])
    
        print(data.decode('gbk'))
    client.close()
    

    上传字典

    #服务端
    import socket
    import json
    import struct
    
    server=socket.socket()
    server.bind(('127.0.0.1',8888))
    server.listen(5)
    
    while True:
        conn,addr=server.accept()
        while True:
            try:
                headers=conn.recv(4)
                data_len=struct.unpack('i',headers)[0]
                bytes_data=conn.recv(data_len)
                #先解码再反序列化
                back_dic=json.loads(bytes_data.decode('utf-8'))
                print(back_dic)
            except Exception as e:
                print(e)
                break
        conn.close()
    
    #客户端
    import socket
    import struct
    import json
    import time
    
    cilent=socket.socket()
    cilent.connect(('127.0.0.1',8888))
    while True:
        send_dic={
            'file_name':'nick真实写真集.avi',
            'file_size':1000000
        }
        #json序列化,并转换成bytes类型数据
        json_data=json.dumps(send_dic)
        bytes_data=json_data.encode('utf-8')
    
        # 先做报头
        headers=struct.pack('i',len(bytes_data))
        cilent.send(headers)
        cilent.send(bytes_data)
        time.sleep(3)
    

    上传大文件

    #服务端
    import socket
    import json
    import struct
    
    server=socket.socket()
    
    server.bind(('127.0.0.1',8888))
    
    server.listen(3)
    while True:
        conn,addr=server.accept()
        while True:
            try:
                #获取字典报头
                headers=conn.recv(4)
                #解包获取字典数据长度
                data_len=struct.unpack('i',headers)[0]
                #获取字典真实数据
                bytes_dic=conn.recv(data_len)
                #樊=反序列得到字典
                back_dic=json.loads(bytes_dic.decode('utf-8'))
                print(back_dic)
                #得到字典的文件名以及视频文件按的大小
                file_name=back_dic['file_name']
                file_size=back_dic['file_size']
    
                init_data=0
                #打开文件 准备写入
                with open(file_name,'wb') as f:
                    while init_data<file_size:
                        data=conn.recv(1024)
                        f.write(data)
                        init_data+=len(data)
                        num=init_data/file_size
                        print(f'已接受{num:.2%}')
                    print(f'{file_name}接收完毕')
            except Exception as e:
                print(e)
                break
        conn.close()
    
    #客户端
    import socket
    import struct
    import json
    
    client=socket.socket()
    client.connect(('127.0.0.1',8888))
    
    #打开一个视频文件,获取视频数据大小
    with open(r'C:UserszqfDesktop新建文件夹八重樱_桃源恋歌_1080p.mp4','rb') as f:
        movie_bytes=f.read()
    
    # 为视频文件组织一个字典,字典内有视频文件按的名称和大小
    send_dic={
        'file_name':'八重樱-桃源恋歌',
        'file_size':len(movie_bytes)
    }
    
    # 先打包字典 发送报头,再发送字典真实数据
    json_data=json.dumps(send_dic)
    bytes_data=json_data.encode('utf-8')
    headers=struct.pack('i',len(bytes_data))
    
    # 发送报头
    client.send(headers)
    #发送字典真实数据
    client.send(bytes_data)
    
    # 发送视频真实数据
    init_data=0
    with open(r'C:UserszqfDesktop新建文件夹八重樱_桃源恋歌_1080p.mp4','rb') as f:
        while init_data<len(movie_bytes):
            send_data=f.read(1024)
            client.send(send_data)
            num=init_data/len(movie_bytes)
            print(f'数据传输{num:.2%}')
            init_data+=len(send_data)
    

    UDP

    是一种传输协议

    1.不需要建立双向管道

    2.不会粘包

    3.客户端给服务端发送数据,不需要等待服务端返回接受成功

    4.数据容丢失,数据不安全

    -TCP:好比打电话

    -UDP:好比发短信

    #服务端
    import socket
    #.SOCK_DGRAM代表了UDP
    server=socket.socket(type=socket.SOCK_DGRAM)
    #绑定了ip+port
    server.bind(('127.0.0.1',8888))
    
    msg,addr=server.recvfrom(1024)
    msg1,addr1=server.recvfrom(1024)
    msg2,addr2=server.recvfrom(1024)
    
    print(msg,msg1,msg2)
    
    
    #客户端
    import socket
    
    client=socket.socket(type=socket.SOCK_DGRAM)
    
    server_ip_port=(('127.0.0.1',8888))
    
    client.sendto(b'hello',server_ip_port)
    client.sendto(b'hello',server_ip_port)
    client.sendto(b'hello',server_ip_port)
    client.sendto(b'hello',server_ip_port)
    client.sendto(b'hello',server_ip_port)
    

    QQ聊天室

    #服务端
    import socket
    
    server=socket.socket(type=socket.SOCK_DGRAM)
    
    server.bind(('127.0.0.1',8888))
    
    while True:
        msg,addr=server.recvfrom(1024)
        print(addr)
        print(msg.decode('utf-8'))
    
        send_msg=input("客户端向服务端发消息").encode('utf-8')
        server.sendto(send_msg,addr)
    
    #客户端
    import socket
    
    client=socket.socket(type=socket.SOCK_DGRAM)
    
    server_ip_port=('127.0.0.1',8888)
    while True:
        send_msg=input('客户端向服务端发消息').encode('utf-8')
        client.sendto(send_msg,server_ip_port)
    
        msg=client.recv(1024)
        print(msg.decode('utf-8'))
    

    SocketServer

    python内置模块,可以简化socket套接字服务端代码

    -简化TCP/UDP服务代码

    -必须要创建一个类

    #服务端
    import socketserver
    
    #必须定义类
    #TCP:必须继承BaseRequestHandler类
    class MyTcpServer(socketserver.BaseRequestHandler):
        def handle(self):
            print(self.client_address)
            while True:
                try:
                    #request.recv==conn.recv
                    data=self.request.recv(1024).decode('utf-8')
                    send_msg=data.upper()
                    self.request.send(send_msg.encode('utf-8'))
    
                except Exception as e:
                    print(e)
                    break
    
    if __name__ == '__main__':
        #socketserver.TCPServer只能一个服务
        # server=socketserver.TCPServer(
        #     ('127.0.0.1',8888),MyTcpServer
        # )
        #
        #socketserver.ThreadingTCPServer 多个服务
        server=socketserver.ThreadingTCPServer(
            ('127.0.0.1', 8888), MyTcpServer
        )
        server.serve_forever()
    
    #客户端
    import socket
    client=socket.socket()
    
    client.connect(
        ('127.0.0.1',8888)
    )
    while True:
        send_msg=input('客户端:')
        client.send(send_msg.encode('utf-8'))
        back_msg=client.recv(1024)
        print(back_msg.decode('utf-8'))
    
    
    
  • 相关阅读:
    默认约束(十六)
    唯一约束(十五)
    主键约束(十四)
    自动编号(十三)
    空值(NULL)和非空(NOT NULL)(十二)
    Codeforces Round #249 (Div. 2) A B
    MySQL 採用Xtrabackup对数据库进行全库备份
    强算KMeans聚类算法演示器
    提高短信营销效果的四大技巧分析
    14年7月总结
  • 原文地址:https://www.cnblogs.com/zqfzqf/p/12592739.html
Copyright © 2011-2022 走看看