用python自己实现一个文件传输。其实python的ftplib模块中封装好了实现FTP传输的功能。但是为了理解文件传输机制,决定自己写一个。
客户端可以向服务器上传和下载文件。
get从服务器下载,post向服务器上传文件。
工程主要目录:
get方法流程图:
put方法和get方法差不多,只是由客户端发送文件,服务器接收
# -*- 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操作
客户端:
服务器: