python网络编程--FTP上传文件示例

1.基础版(供学习了解原理使用,low)

server服务端

import socket
import struct
import json  

server = socket.socket()
ip_port = ('127.0.0.1', 8001)
server.bind(ip_port)
server.listen()
conn, addr = server.accept()

head_len_msg = conn.recv(4)
head_len = struct.unpack('i',head_len_msg)[0]
head_byte = conn.recv(head_len)
head = json.loads(head_byte.decode('utf-8'))
file_size = head['size']
size = 0
with open('文件副本',mode='wb') as f1:
    while file_size:
        if file_size >= 1024:
            line = conn.recv(1024)
            f1.write(line)
            file_size -= 1024
        else:
            content = conn.recv(1024)
            break
conn.close()
server.close()

  

client客户端

import os
import socket
import struct
import json

client = socket.socket()
client.connect(('127.0.0.1', 8001))

buffer = 1024
filepath = input('请输入文件路径')
filesize = os.path.getsize(filepath)
head = {'size':os.path.getsize(filepath)}
head_json = json.dumps(head)
head_byte = head_json.encode('utf-8')
head_len = len(head_byte)
pack_len = struct.pack('i', head_len)
client.send(pack_len)
client.send(head_byte)

with open(filepath,mode='rb') as f:
    while filesize:
        if filesize>buffer:
            content = f.read(buffer)
            client.send(content)
            filesize -= buffer
        else:
            content = f.read(filesize)
            client.send(content)
            break

 

2.升级版(正常使用)

封装了报头,解决了粘包问题的FTP传文件 

server服务端

import struct,json,socket
import subprocess
import os  # 引入所需模块

# 面向对象,定义server类 class MyTcpServer: address_family = socket.AF_INET # 定义socket的family属性,使用ipv4 socket_type = socket.SOCK_STREAM # 定义面向类型,面向流,是tcp传输 allow_reuse_address = False # 服务器地址复用, 默认不允许 max_packet_size = 8192 # 传包最大缓冲长度 coding = 'utf-8' # 编码类型 request_queue_size = 5 # 等待队列数,listen()时使用 server_dir = 'file_upload' # 服务器存放上传文件的文件夹名 , 测试时 要新建一个名为file_upload的文件夹 def __init__(self, server_address, bind_and_active = True): # 初始化方法, 传入服务器地址, 是否要开始监听 self.server_address = server_address self.socket = socket.socket() # 创建socket对象 if bind_and_active: # 如果需要连接 try: # 异常处理 self.server_bind() # 绑定端口 self.server_activate() # 监听开始 except: self.server_close() # 服务器关闭 raise def server_bind(self): # bind() 方法 if self.allow_reuse_address: # 如果允许复用 self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) # 服务器允许端口复用写这句话 self.socket.bind(self.server_address) # socket对象绑定服务器地址 self.server_address = self.socket.getsockname() # 获取套接字的名称 ,服务器的地址 def server_activate(self): # 服务器listen()方法 self.socket.listen(self.request_queue_size) def server_close(self): # close()方法 的函数 self.socket.close() def get_request(self): # 得到请求 accpt()方法的函数 return self.socket.accept() def close_request(self,request): # 关闭请求的方法 request.close()
def run(self): # run方法 while 1: self.conn,self.client_addr = self.get_request() # 获得conn ,addr print('from client ', self.client_addr) while 1: try: head_struct = self.conn.recv(4) # 接收4位 这4位是自定义报头的长度 if not head_struct: break # 如果 不是, 结束 head_len = struct.unpack('i', head_struct)[0] # 报头的长度 通过struct解包得出,解包为元组 第0项是报头长度,此时类型为字节 head_json = self.conn.recv(head_len).decode(self.coding) # 将长度解码 head_dic = json.loads(head_json) # 并用json转化为字典 print(head_dic) # 打印报头 cmd = head_dic['cmd'] # cmd 这一项等于 字典中的cmd选项 就是要实现什么功能 if hasattr(self,cmd): # 如果自己有cmd 这个功能 func = getattr(self,cmd) # 得到这个方法 func(head_dic) # 运行这个功能
except Exception: break def put(self,args): # 接收文件 file_path = os.path.normpath(os.path.join(self.server_dir,args['filename'])) # 文件路径 将接收的文件名和自己的路径拼接 并标准化 filesize = args['filesize'] # 文件大小为报头中标出的 recv_size = 0 # 接收的长度 先定义为0 print('----->',file_path) with open(file_path,'wb') as f: # 开始接收长度 while recv_size < filesize: recv_data = self.conn.recv(self.max_packet_size) # recv最大可接收缓存为定义好的最大长度 f.write(recv_data) # 写入文件 recv_size += len(recv_data) print('recvsize: %s filesize: %s' %(recv_size,filesize)) tcpserver1 = MyTcpServer(('127.0.0.1', 8001)) tcpserver1.run()

  

client客户端

import os
import socket,json,subprocess,struct

class MyTcpClient:
    addresss_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM
    allow_reuse_address = False
    max_packet_size = 8192
    coding = 'utf-8'
    request_queue_size = 5
    def __init__(self, server_address, connect = True):
        self.servver_address = server_address
        self.socket = socket.socket(self.addresss_family,self.socket_type)
        if connect:
            try:
                self.client_connect()
            except:
                self.client_close()
                raise

    def client_connect(self):
        self.socket.connect(self.servver_address)

    def client_close(self):
        self.socket.close()

    def run(self):
        while True:
            inp = input('>>: ').strip()
            if not inp:continue
            l = inp.split()
            cmd = l[0]  # 运行的功能 为切出的第一项
            if hasattr(self,cmd):
                func = getattr(self,cmd)
                func(l)

    def put(self,args):  # 传文件
        cmd = args[0]  # 报头执行的命令 
        filename = args[1]  # 文件名
        if not os.path.isfile(filename):  # 如果这个路径是文件
            print('file:%s is not exists' % filename)  # 如果不是为空
        else:
            filesize = os.path.getsize(filename)  # 得到文件大小

        head_dic = {'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}  # 定义报头
        print(head_dic)  # 打印一下报头看看
        head_json = json.dumps(head_dic)  # 用json转化为字符串
        head_json_bytes = bytes(head_json, encoding=self.coding)  # 编码成字节准备传输

        head_struct = struct.pack('i', len(head_json_bytes))  # 用struct模块封包 把报头长度转化为4个字节
        self.socket.send(head_struct)  # 发送报头长度
        self.socket.send(head_json_bytes)  # 发送报头
        send_size = 0
        with open(filename,'rb') as f:
            for line in f:
                self.socket.send(line)
                send_size += len(line)
                print(send_size)
            else:
                print('upload successful')

client = MyTcpClient(('127.0.0.1', 8001))
client.run()

  

原文地址:https://www.cnblogs.com/robertx/p/10228885.html