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()
    

    传大文件

    和上面重复了

  • 相关阅读:
    平衡二叉树之RB树
    平衡二叉树之AVL树
    实现哈希表
    LeetCode Median of Two Sorted Arrays
    LeetCode Minimum Window Substring
    LeetCode Interleaving String
    LeetCode Regular Expression Matching
    PAT 1087 All Roads Lead to Rome
    PAT 1086 Tree Traversals Again
    LeetCode Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/jimGraymane/p/11700418.html
Copyright © 2011-2022 走看看