用python实现FTP传输


用python自己实现一个文件传输。其实python的ftplib模块中封装好了实现FTP传输的功能。但是为了理解文件传输机制,决定自己写一个。

客户端可以向服务器上传和下载文件。

get从服务器下载,post向服务器上传文件。


工程主要目录:




get方法流程图:


扫描二维码关注公众号,回复: 11270127 查看本文章

put方法和get方法差不多,只是由客户端发送文件,服务器接收



Put方法流程图:




客户端代码:
# -*- coding: utf-8 -*-
##
# ftp_client
# Created on 2016 12 15
# @author:huangpingyi
##
import socket
import os

class FTP(object):
    def __init__(self, host, port):
        self.host = host
        self.port = port
    def put(self,msg):  #put local_file
        print '--put:', msg
        if len(msg) > 0:
            remote_filename = msg[0]
            #判断文件是否存在
            if os.path.isfile(remote_filename):
                 file_size = os.path.getsize(remote_filename)
                 #发送文件名和大小给服务
                 cmd_msg = "file_transfer|put|%s|%s" % (remote_filename,file_size)
                 self.sock.send(cmd_msg)
                 #服务器返回应答
                 feedback = self.sock.recv(1024)
                 print '--feedback:',feedback
                 #如果服务器准备好,就开始传输
                 if feedback.startswith("file_transfer|put|ready"):
                     f = file( remote_filename,'rb')
                     send_size =0
                     #文件很大,传送不完,每次以1024传输
                     while not file_size == send_size:
                        if file_size-send_size>1024:
                            data = f.read(1024)
                            send_size += 1024
                       #最后一轮
                        else:
                            data = f.read(file_size-send_size)
                            send_size+=file_size-send_size
                        self.sock.send(data)
                     else:
                       print "--send file %s " % remote_filename
                       f.close()
                 else:
                   print feedback
    def get(self,msg):  #get remote_file
        print '--get:', msg
        if len(msg) > 0:
            remote_filename = msg[0]
            #发送get消息给服务器
            cmd_msg = "file_transfer|get|%s" % remote_filename
            self.sock.send(cmd_msg)
            #服务器查看文件是否存在并响应
            feedback = self.sock.recv(1024)
            print '--feedback:',feedback
            #如果文件存在,服务器发送文件大小过来
            if feedback.startswith("file_transfer|get|ready"):
                #文件大小
                file_size = int(feedback.split("|")[-1])
                #客户端发送准备接收
                ack_msg = "file_transfer|get|recv|ready"
                self.sock.send(ack_msg)
                #建立文件
                f = file("recv\%s"% remote_filename,'wb')
                #客户端接受
                #收到的数据和总大小比较
                recv_size =0
                #文件很大,接受不完,开始计数,每次接收1024
                while not file_size == recv_size:
                    if  file_size-recv_size>1024:
                        data = self.sock.recv(1024)
                        recv_size += len(data)#收到的小于1024,实时性不一定是1024
                    #最后一轮
                    else:
                        data = self.sock.recv(file_size-recv_size)
                        recv_size+=file_size-recv_size
                    f.write(data)
                else:
                 print "--recv file %s " % remote_filename
                 f.close()
            else:
                print feedback

    def interactive(self):
        #客户端交互
         while True:
             user_input = raw_input("ftp_client::").strip()
             if len(user_input) == 0:
                 continue
             cmd = user_input.split()
             if  hasattr(self, cmd[0]):#用反射判断用户是要get还是put
                                       #判断对象是否有cmd[0]方法
                 func = getattr(self, cmd[0])#有则将cmd[0]方法赋值
                 func(cmd[1:])#把后面的参数传给cmd[0]方法,并执行cmd[0]函数
             else:#如果是其他命令,就打印错误
                 print "\033[31;1mWrong cmd usage!\033[0m"


    def connect(self):
        #连接
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((self.host, self.port))
        self.interactive()

if __name__ == '__main__':
    ftp = FTP('localhost',7126 )
    ftp.connect()


服务器端代码:
# -*- coding: utf-8 -*-
##
# socket_server
# Created on 2016 12 15
# @author:huangpingyi
##

import SocketServer
import os

class MyTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        while True:
            data = self.request.recv(1024).strip()
            data = data.split("|")
            if hasattr(self, data[0]):
                func = getattr(self, data[0])
                func(data[1:])#将后面参数传入file_transfer

    def file_transfer(self,msg):
        if msg[0] == "get":
            print "----going to send file:%s to client" % msg[1]
            filename = msg[1]
            if os.path.isfile(filename):
            #判断文件存在
            #如果文件存在,就判断文件大小
               file_size = os.path.getsize(filename)
               #将文件大小发送給客户端
               ack_msg = "file_transfer|get|ready|%s" % file_size
               self.request.send(ack_msg)
               client_ack = self.request.recv(1024)
               print '-->client ack:', client_ack
               #如果客户端准备好就开始传输文件
               if client_ack.startswith("file_transfer|get|recv|ready"):
                   f = file(filename, "rb")
                   send_size =0
                   Flag = True
                   while Flag:
                       if send_size+1024 > file_size:
                           data = f.read(file_size-send_size)
                           Flag = False
                       else:
                           data = f.read(1024)
                           send_size+=1024
                       self.request.send(data)
                   print '--file %s send done---' % filename
                   f.close()

            else:
               ack_msg = "file_transfer|get|doesn't exist"
               self.request.send(ack_msg)

        if msg[0] == "put":
                print "----going to put file:%s" % msg[1]
                #获取文件名字和大小
                file_name = msg[1]
                file_size = msg[2]
                base_path = "D:\untitled4"
                #发送准备好接收的请求
                ack_msg = "file_transfer|put|ready"
                self.request.send(ack_msg)
                recv_size = 0
               #上传文件路径拼接
                file_dir = os.path.join(base_path,file_name)
                f = file(file_dir,'wb')
                Flag = True
                while Flag:
                #未上传完毕,
                   if int(file_size)>recv_size:
                    #最多接收1024,可能接收的小于1024
                      data =self.request.recv(1024)
                      recv_size+=len(data)
                    #上传完毕,则退出循环
                   else:
                       recv_size = 0
                       Flag = False
                       continue
                    #写入文件
                   f.write(data)
                print 'upload successed.'
                f.close()


if __name__ == '__main__':
    HOST,PORT = 'localhost',7126
    server = SocketServer.ThreadingTCPServer((HOST,PORT),MyTCPHandler)
    server.serve_forever()


测试效果:

执行get 操作

客户端:

服务器:

       

    刷新recv文件夹,便可看见test.txt

                                                                                                                                                                                                                                 


  执行put操作      

客户端:     

 

  服务器:                                                                                                                                                                                                                                                                                                       



                                                     

猜你喜欢

转载自blog.csdn.net/qq_23948283/article/details/53573606