zoukankan      html  css  js  c++  java
  • 网络编程II

    subprocess模块
    粘包问题
    UDP协议
    SocketServer模块
    上传大文件

    subprocess

    subprocess模块用于和操作系统的cmd交流,实现操作系统的命令执行和对结果的展示

    import subprocess
    cmd=input('cmd>>:')
    cac=subprocess.check_output(cmd)
    print(cac)
    
    import subprocess
    
    command=input('cmd>>:')
    obj=subprocess.Popen(
    
        command,#命令
        shell=True,#这个必须是true
        stdout=subprocess.PIPE,#返回正确的结果
        stderr=subprocess.PIPE,#返回错误的结果
    )
    
    result=obj.stdout.read()+obj.stderr.read()
    print(result.decode('gbk'))
    

    粘包问题

    服务器第一次发送的数据,客户端无法精确一次性接受完毕.

    下一次发送的数据与上一次的数据黏在一起了,发生这种现象的主要原因是无法预测当前接受的数据大小,而且发送数据的体积小,时间间隔较短,就会被一次性打包送走.

    TPC协议

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

    解决粘包问题的方法有:

    1.使用struct模块.

    struct模块是一个可以将数据大小长度都压缩成固定长度的一个标记

    struct模块先使用pack方法根据数据的二进制长度生成一个大小为4的报头.通过unpack在另一端解压这个包,得到想要发送数据的大小.unpack返回的是一个元组

    在python中只有字符串才能直接编码转换成二进制类型.其他的数据类型只能先转换成json和pickle数据类型才能转二进制

    客户端:

    import socket
    import struct
    import json
    
    client = socket.socket()
    
    client.connect(
        ('127.0.0.1', 9527)
    )
    
    file_path=input('请输入文件的路径')
    file_name=input('请输入文件的名字')
    # 1.打开一个视频文件,获取视频数据大小
    with open(rf'{file_path}{file_name}', 'rb') as f:
        movie_bytes = f.read()
        # 关闭文件
    
    # 2.为视频文件组织一个字典,字典内有视频的名称,视频大小
    send_dic = {
        'file_name': f'{file_name}',
        'file_size': len(movie_bytes)  # 10G
    }
    
    # 3.先打包字典,发送headers报头,再发送真实字典数据
    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)
    
    # 4.接着发送真实视频文件数据
    init_data = 0
    num = 1
    with open(r'D:jason真实写真集.mp4', 'rb') as f:
        while init_data < len(movie_bytes):
            # 最后一次获取,有多少拿多少
            send_data = f.read(1024)
            print(send_data, num)
            num += 1
            # 每次发送1024数据
            client.send(send_data)
            # 为初始发送数据 + 已发送数据的长度
            init_data += len(send_data)
    
    
    
    

    服务端:

    import socket
    import json
    import struct
    server = socket.socket()
    server.bind(
        ('127.0.0.1', 9527)
    )
    server.listen(5)
    
    while True:
        conn, addr = server.accept()
        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)
    
            # 拿到字典的文件名,文件大小
            file_name = back_dic.get('file_name')
            file_size = back_dic.get('file_size')
    
            init_data = 0
            # 1.以文件名打开文件,准备写入
            with open(file_name, 'wb') as f:
    
                # 一点一点接收文件,并写入
                while init_data < file_size:
                    data = conn.recv(1024)
                    # 2.开始写入视频文件
                    f.write(data)
                    init_data += len(data)
    
                print(f'{file_name}接收完毕!')
    
        except Exception as e:
            print(e)
            break
    
    conn.close()
    
    

    UDP协议

    UDP协议的特点是:

    不需要先建立连接

    不会粘包

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

    数据容易丢失,数据不安全

    TCP就好比在打电话

    UDP就好比在发短信

    socketserver

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

    优点是可以简化TCP与UDP服务端的代码

    缺点是必须创建一个类

    # 客户端:
    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'))
    
    
    # 服务端
    
    import socketserver
    
    
    # 定义类
    # TCP: 必须继承BaseRequestHandler类
    class MyTcpServer(socketserver.BaseRequestHandler):
    
        # 必须重写父类的handle, 当客户端连接时会调用该方法
        def handle(self):
            print(self.client_address)
    
            while True:
                try:
                    # 1.接收消息
                    # request.recv(1024) == conn.recv(1024)
                    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
        # )
    
        # ThreadingTCPServer: 有多个技师可服务
        server = socketserver.ThreadingTCPServer(
            ('127.0.0.1', 8888), MyTcpServer
        )
    
        # 永久执行服务
        server.serve_forever()
    

    传大文件

    和上面重复了

  • 相关阅读:
    [SDOI2008]递归数列
    [SCOI2008]奖励关
    [SCOI2010]幸运数字
    [ZJOI2007]矩阵游戏
    [HAOI2006]旅行
    [ZJOI2008]泡泡堂
    [BZOJ1800][Ahoi2009]fly 飞行棋
    [POJ2288]Islands and Bridges
    [LUOGU] 3959 宝藏
    [BZOJ]1029: [JSOI2007]建筑抢修
  • 原文地址:https://www.cnblogs.com/jimGraymane/p/11700418.html
Copyright © 2011-2022 走看看