zoukankan      html  css  js  c++  java
  • Python Socket实现文件上传(TCP协议)

    在TCP协议下通过socket模块实现文件上传

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # desc: tcp_server_file_upload
    
    import socket
    import struct
    import json
    import time
    
    IP_PORT    = ('127.0.0.1', 8080)
    BUFFERSIZE = 1024
    
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  #获取socket对象,并设置通过TCP协议通信
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)#设置连接重用
    tcp_server_socket.bind(IP_PORT) #绑定IP地址和端口
    tcp_server_socket.listen()      #监听,可指定数量
    
    conn, addr = tcp_server_socket.accept() #建立连接
    print('client ip addr:', addr)
    head_struct = conn.recv(4)  #接收定制报头的长度
    head_json_len = struct.unpack('i', head_struct)[0]   #解包,获取定制报头的长度
    head_json = conn.recv(head_json_len).decode('utf-8') #根据上一步解包获得的报头长度,接收报头
    head = json.loads(head_json) #将json字符串类型的报头转化为python对象
    file_size = head['file_size']#获取待接收文件的大小
    file_name = head['file_name']#获取接收文件的名字
    print(time.strftime('%Y-%m-%d %H:%M:%S'),' 开始接收文件...') #打印开始接收文件的时间
    with open(file_name, 'wb') as f:  #以二进制写方式打开文件
        '''
        循环写入接收的文件内容
        '''
        while True:
            if file_size >= BUFFERSIZE:   #如果接收的文件内容大于设置的BUFFERSIZE,就只接收BUFFERSIZE大小的内容
                content = conn.recv(BUFFERSIZE) #接收客服端发送的BUFFERSIZE大小的内容
                f.write(content) #在服务端写入BUFFERSIZE大小的内容
                file_size -= BUFFERSIZE #将待写入的文件大小减去已接收的BUFFERSIZE大小
                '''
                主要是用于服务端和客户端在同一PC上,且写入比读取快,从而导致服务端先行关闭,
                造成客户端连接中断,文件传送不完整
                '''
                time.sleep(0.00001) 
            else:
                content = conn.recv(file_size) #接收文件剩余部分
                f.write(content)
                break
    print(time.strftime('%Y-%m-%d %H:%M:%S'),' 成功接收文件...') #打印文件接收完成时间
    
    conn.close() #关闭连接
    tcp_server_socket.close() #关闭服务端socket
    tcp_server_file_upload
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @desc: tcp_client_file_upload
    
    import socket
    import struct
    import json
    import os
    import time
    
    IP_PORT    = ('127.0.0.1', 8080)
    BUFFERSIZE = 1024
    
    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #获取socket对象
    tcp_client_socket.connect(IP_PORT) #连接服务端
    
    '''
    定制化报头
    '''
    head = {'file_path':r'文件路径',
            'file_name':r'文件名',
            'file_size':0
            }
    
    file_path = os.path.join(head['file_path'], head['file_name']) #获取要上传文件的完整路径
    file_size = os.path.getsize(file_path) #获取文件大小
    head['file_size'] = file_size #将获取到的真实文件大小设置到报头
    
    head_json = json.dumps(head)  #将报头python对象转化为json字符串
    head_bytes = bytes(head_json, encoding='utf-8') #将报头json字符串转化为bytes字节码
    head_struct = struct.pack('i', len(head_bytes)) #将报头bytes字节码以'integer'类型打包为4个字节
    tcp_client_socket.send(head_struct) #发送打包为4个字节的报头
    tcp_client_socket.send(head_bytes)  #发送定制化报头
    print(time.strftime('%Y-%m-%d %H:%M:%S'),' 开始发送文件...') #打印开始发送文件的时间
    with open(file_path, 'rb') as f:    #以二进制读的方式打开文件
        '''
        循环读取文件内容并发送给服务端
        '''
        while True:
            if file_size >= BUFFERSIZE: #如果发送文件的大小大于BUFFERSIZE,只读取BUFFERSIZE大小的内容
                content = f.read(BUFFERSIZE) #读取BUFFERSIZE大小的内容
                tcp_client_socket.sendall(content) #发送读取的文件内容
                file_size -= BUFFERSIZE #文件大小减去已发送文件的大小
            else:
                content = f.read(file_size)  #读取剩余文件内容
                tcp_client_socket.sendall(content) #发送文件读取的文件内容
                break #终止循环
    
    print(time.strftime('%Y-%m-%d %H:%M:%S'),' 文件发送成功...') #大于文件发送完成的时间
    tcp_client_socket.close() #关闭socket
    tcp_client_file_upload
  • 相关阅读:
    vue报错 Do not use built-in or reserved HTML elements as component id:header
    vue 报错./lib/html5-entities.js this relative module was not
    vue报错/ style-loader: Adds some css to the DOM by adding a <style> tag
    vue报错 Module not found: Error: Cannot resolve 'file' or 'directory'
    vue报错 vue-cli 引入 stylus 失败
    oracle 定时任务
    Java 基础面试题
    在Java中调用带参数的存储过程
    Linux安装JDK完整步骤
    Spring中获取数据库表主键序列
  • 原文地址:https://www.cnblogs.com/yueyun00/p/10027033.html
Copyright © 2011-2022 走看看