• python实现简单FTP


    • 需求

    1. 用户登陆  ---configparse 存储信息 进行登录验证
    2. 上传/下载文件        ---get、put函数
    3. 不同用户家目录不同    ----configparse定义家目录
    4. 查看当前目录下文件    ----dir命令,如何进行权限判定,只能进入到自己的目录下面?
    5. 充分使用面向对象知识    -----就是用类、函数
    • 代码结构

    • 服务端

      1 #!/usr/bin/env python
      2 #-*- coding:utf-8 -*-
      3 # @Time    : 2017/12/14 15:25
      4 # @Author  : lichuan
      5 # @File    : 服务端.py
      6 
      7 
      8 import socketserver
      9 import struct
     10 import json
     11 import subprocess
     12 import os
     13 import configparser
     14 from module import common
     15 import subprocess
     16 
     17 class My_FtpServer(socketserver.BaseRequestHandler):
     18 
     19     def handle(self):
     20         # while True:
     21         try:
     22             name = self.name_check()    #进行用户名验证
     23             self.path = common.get_home_path(name)   #根据用户名获取家目录
     24             if not os.path.exists(self.path):
     25                 os.mkdir(self.path)
     26             # os.chdir(path)
     27             print(os.getcwd())
     28             while True:
     29                 data=self.request.recv(8)   #接收命令长度
     30                 if not data:break   #防止在linux、mac等系统中会有问题
     31                 msg_length=struct.unpack('q',data)[0]  #是一个元组形势的数据,包含命令长度
     32                 cmd = self.request.recv(msg_length).decode('utf-8')
     33                 if cmd.upper() == 'QUIT':  #quit 进行退出
     34                     print('break')
     35                     break
     36                 if hasattr(self,cmd.split()[0]): #收到的消息,进行切分,拿出第一个进行判断
     37                     print(cmd.split()[0])
     38                     func = getattr(self,cmd.split()[0])
     39                     func(cmd)
     40                 else:  #如果没有函数,则进行执行命令
     41                     os.chdir(self.path)
     42                     res=subprocess.Popen(cmd,
     43                                      shell=True,
     44                                      stdout=subprocess.PIPE,
     45                                      stderr=subprocess.PIPE)
     46                     err = res.stderr.read()
     47                     if err:
     48                         back_msg=err
     49                     else:
     50                         back_msg=res.stdout.read()
     51                         if cmd.split()[0] == 'cd':
     52                             new_path = os.getcwd()+os.sep+cmd.split()[1]
     53                             if self.path in new_path:
     54                                 print('self.path',self.path)
     55                                 print('new_path',new_path)
     56                                 self.path = new_path
     57                     print(self.path)
     58                     self.send_msg(back_msg)
     59         except Exception as e:
     60             print("Error:",e)
     61             print('handle exception!')
     62 
     63     def send_header(self,file_info): #发送报头
     64         # file_info = {'cmd': cmd,'status': status}
     65         f_head = json.dumps(file_info)  #json化代码,用于传输
     66         f_head_bytes = bytes(f_head, encoding='utf-8') #变成bytes类型
     67         self.request.send(struct.pack('q', len(f_head_bytes)))  # 传报头长度过去
     68         self.request.sendall(f_head_bytes)  # 传报头过去
     69 
     70     def get(self,cmd):
     71         print('----get function----')
     72         # print(os.getcwd())
     73         os.chdir(self.path)
     74         l = cmd.split()
     75         if len(l) != 2:
     76             print('get command is worng!')
     77             return
     78         # BASE_DIR = os.path.dirname(os.path.abspath(__file__))
     79         f = l[1]
     80         if os.path.exists(f):
     81             file_path = os.path.abspath(f)
     82         else:
     83             print('file not exists!')
     84             return
     85         print('file path:',os.path.abspath(file_path))
     86         if os.path.isfile(file_path) and self.path in file_path:
     87             file_size = os.path.getsize(file_path)
     88             file_md5 = common.GetFileMd5(file_path)  # 获取文件的md5值
     89             status = 'OK'
     90             file_info = {'cmd': cmd, 'filename': os.path.basename(file_path), 'file_size': file_size, 'md5': file_md5,'status':status}
     91             # f_head = json.dumps(file_info)
     92             # print(type(f_head))
     93             # f_head_bytes = bytes(f_head, encoding='utf-8')
     94             # print(f_head_bytes,type(f_head_bytes),type(f_head))
     95             # print('len:',len(f_head))
     96             # self.request.send(struct.pack('q', len(f_head_bytes)))  # 传报头长度过去
     97             # self.request.sendall(f_head_bytes)  # 传报头过去
     98             self.send_header(file_info)
     99             with open(file_path, 'rb') as read_f:
    100                 for line in read_f:
    101                     self.request.send(line)  # 传文件过去
    102         else:
    103             print('权限不够或者不是文件')
    104             status = 'ERROR'
    105             file_info = {'cmd': cmd,'status': status}
    106             self.send_header(file_info)
    107 
    108 
    109     def put(self,cmd):
    110         print('----put function----')
    111         os.chdir(self.path)
    112         l = cmd.split()
    113         if len(l) != 2:
    114             print('put command is worng!')
    115             return
    116         head_l=self.request.recv(8) #接收报头长度
    117         longth = int(struct.unpack('q',head_l)[0]) #接收到的应该是个元组,取第一位,即长度
    118         file_json = self.request.recv(longth).decode('utf-8')
    119         head_dic = json.loads(file_json)
    120         status = head_dic['status']
    121         if status == 'OK':
    122             file_name=head_dic['filename']
    123             file_size=head_dic['file_size']
    124             recv_size = 0
    125             with open(file_name,'wb') as write_f:
    126                 while recv_size < file_size:
    127                     res=self.request.recv(1024)
    128                     recv_size+=len(res)
    129                     write_f.write(res)
    130                     print(recv_size,file_size)
    131             file_path=os.path.abspath(file_name)
    132             # print('file_name:',file_name)
    133             print('file_path:',file_path)
    134             file_md5=common.GetFileMd5(file_path)
    135             # print(file_md5)
    136             # print(head_dic['md5'])
    137             if file_md5 == head_dic['md5']:
    138                 print('文件传输成功')
    139             else:
    140                 print('文件不一致')
    141                 os.remove(file_path)
    142 
    143     def send_msg(self,msg):#用于发送信息
    144         self.head_l = struct.pack('q',len(msg))
    145         self.request.send(self.head_l)
    146         self.request.sendall(msg)
    147 
    148     #进行用户名密码验证的函数
    149     def name_check(self):
    150         while True:
    151             name = self.request.recv(1024).decode('utf-8')
    152             self.request.send('0'.encode('utf-8'))
    153             passwd=self.request.recv(1024).decode('utf-8')
    154             if common.login(name,passwd):
    155                 self.request.send('0'.encode('utf-8'))
    156                 return name
    157             else:
    158                 self.request.send('1'.encode('utf-8'))
    159                 continue
    160 
    161     #执行dir命令显示目录下的内容
    162     def show_path_content(self,path):
    163         print('show path'+path)
    164         cmd = 'dir ' + path
    165         res1 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    166         return res1.stdout.read().decode('gbk')
    167 
    168 if __name__ == '__main__':
    169     fserver = socketserver.ThreadingTCPServer(('127.0.0.1',8001),My_FtpServer)
    170     fserver.serve_forever()
    171     fserver.server_close()
    172     # for l in os.listdir(os.getcwd()):
    173     #     print(l)
    174     # for i in os.walk(os.path.dirname(os.path.dirname((os.path.abspath(__file__))))):
    175     #     print(i)
    服务端.py
    • 客户端

      1 #!/usr/bin/env python
      2 #-*- coding:utf-8 -*-
      3 # @Time    : 2017/12/14 15:25
      4 # @Author  : lichuan
      5 # @File    : 客户端.py
      6 
      7 
      8 #_*_coding:utf-8_*_
      9 
     10 import time
     11 import socket
     12 import struct
     13 import json
     14 import os
     15 from module import common
     16 
     17 BUFSIZE=1024
     18 
     19 
     20 class FTP_ClientServer:
     21     def __init__(self,ip_port,logined=False):
     22         self.ip_port=ip_port
     23         self.logined = logined
     24         self.socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     25         try:
     26             self.socket.connect(ip_port)
     27         except:
     28             self.socket.close()
     29             raise
     30 
     31     def run(self):
     32         while True:
     33             if not self.logined:
     34                 self.login()
     35             else:
     36                 msg = input('>>:').strip()
     37                 msg_longth=struct.pack('q',len(msg))
     38                 self.socket.send(msg_longth)
     39                 self.socket.sendall(msg.encode('utf-8'))
     40                 if msg.upper() == 'QUIT':
     41                     break
     42                 if hasattr(self,msg.split()[0]):
     43                     func=getattr(self,msg.split()[0])
     44                     func(msg)
     45                 else:  #传送命令过去的逻辑
     46                     recv = self.socket.recv(8)
     47                     data = struct.unpack('q',recv) #返回的是一个元组,(123,),123是长度
     48                     print(data)
     49                     longth = data[0]
     50                     recv_size = 0
     51                     recv_data = b''
     52                     while recv_size < longth:
     53                         recv_data+=self.socket.recv(1024)
     54                         recv_size+=1024
     55                     print(recv_data.decode('gbk'))
     56 
     57     #程序开始时,进行登录验证的函数
     58     def login(self):
     59         name = input('username:').strip()
     60         passwd = input('password:').strip()
     61         if len(name) == 0: return False
     62         if len(passwd) == 0: return False
     63         self.socket.send(name.encode('utf-8'))  # 发送name过去进行验证
     64         recv = self.socket.recv(1)
     65         if recv.decode('utf-8') != '0':  # name返回结果不为0,说明name不存在
     66             print('name error')
     67             return False
     68         self.socket.send(passwd.encode('utf-8'))
     69         recv = self.socket.recv(1)
     70         if recv.decode('utf-8') != '0':  # passwd返回结果不为0,说明passwd错误
     71             print('passwd error')
     72             return False
     73         print('login successful!')
     74         self.logined = True
     75         return True
     76 
     77     def recv_msg(self):
     78         head_l = self.socket.recv(8)
     79         data_head = struct.unpack('q',head_l)
     80 
     81     def get(self,cmd):
     82         l = cmd.split()
     83         if len(l) != 2:
     84             print('get command is worng!')
     85             return
     86         head_l = self.socket.recv(8)  # 接收报头长度
     87         longth = int(struct.unpack('q', head_l)[0])  # 接收到的应该是个元组,取第一位,即长度
     88         file_json = self.socket.recv(longth).decode('utf-8')
     89         head_dic = json.loads(file_json)
     90         status = head_dic['status']
     91         if status == 'OK':
     92             file_name = head_dic['filename']
     93             file_size = head_dic['file_size']
     94             recv_size = 0
     95             with open(file_name, 'wb') as write_f:
     96                 while recv_size < file_size:
     97                     res = self.socket.recv(1024)
     98                     recv_size += len(res)
     99                     write_f.write(res)
    100                     print(recv_size, file_size)
    101             file_path = os.path.abspath(file_name)
    102             # print('file_name:',file_name)
    103             print('file_path:', file_path)
    104             file_md5 = common.GetFileMd5(file_path)
    105             # print(file_md5)
    106             # print(head_dic['md5'])
    107             if file_md5 == head_dic['md5']:
    108                 print('文件传输成功')
    109             else:
    110                 print('文件不一致')
    111                 os.remove(file_path)
    112         else:
    113             print('权限不够或者不是文件')
    114 
    115     def put(self,msg):
    116         l=msg.split()
    117         if len(l) != 2:
    118             print('put command is worng!')
    119             return
    120         BASE_DIR=os.path.dirname(os.path.abspath(__file__))
    121         f=l[1]
    122         if os.path.exists(f):
    123             file_path = os.path.abspath(f)
    124         else:
    125             print('file not exists!')
    126             return
    127         if os.path.isfile(file_path):
    128             file_size = os.path.getsize(file_path)
    129             file_md5 = common.GetFileMd5(file_path)  #获取文件的md5值
    130             status = 'OK'
    131             file_info = {'cmd':msg,'filename':os.path.basename(file_path),'file_size':file_size,'md5':file_md5,'status':status}
    132             self.send_header(file_info)
    133             # f_head=json.dumps(file_info)
    134             # print(type(f_head))
    135             # f_head_bytes = bytes(f_head,encoding='utf-8')
    136             # print(f_head_bytes,type(f_head_bytes),type(f_head))
    137             # print('len:',len(f_head))
    138             # self.socket.send(struct.pack('q',len(f_head_bytes))) #传报头长度过去
    139             # self.socket.sendall(f_head_bytes)     #传报头过去
    140             num=0
    141             with open(file_path,'rb') as read_f:
    142                 for line in read_f:
    143                     self.socket.send(line)       #传文件过去
    144                     # num+=1
    145                     # print(num)
    146         else:
    147             status = 'ERROR'
    148             file_info = {'cmd': msg,'status': status}
    149             self.send_header(file_info)
    150 
    151     def send_header(self,file_info): #发送报头
    152         # file_info = {'cmd': cmd,'status': status}
    153         f_head = json.dumps(file_info)  #json化代码,用于传输
    154         f_head_bytes = bytes(f_head, encoding='utf-8') #变成bytes类型
    155         self.socket.send(struct.pack('q', len(f_head_bytes)))  # 传报头长度过去
    156         self.socket.sendall(f_head_bytes)  # 传报头过去
    157 
    158 if __name__ == '__main__':
    159     ip_port = ('127.0.0.1', 8001)
    160     f=FTP_ClientServer(ip_port)
    161     f.run()
    客户端.py
    • 用户定义文件

    1 [egon]
    2 name = egon
    3 home_path = egon
    4 passwd = bc5b9cb3e4ab483335edab3347f3c102
    5 
    6 [alex]
    7 name = alex
    8 home_path = alex
    9 passwd = bc5b9cb3e4ab483335edab3347f3c102
    users.cfg
    • 公共定义函数文件

     1 #!/usr/bin/env python
     2 #-*- coding:utf-8 -*-
     3 # @Time    : 2017/10/20 15:46
     4 # @Author  : lichuan
     5 # @File    : common.py
     6 
     7 import hashlib
     8 import os
     9 import re
    10 from log import my_log_settings
    11 import logging
    12 import pickle
    13 import configparser
    14 
    15 def login(name,passwd):
    16     path = os.path.dirname(os.path.abspath(__file__))+os.sep+'users.cfg'
    17     config = configparser.ConfigParser()
    18     config.read(path)
    19     # print(config.sections())
    20     if name not in config.sections():
    21         print('name is wrong!')
    22         return False
    23     encrypt_passwd = encrypt(passwd)
    24     # print(encrypt_passwd)
    25     p = config.get(name,'passwd')
    26     # print(p)
    27     if encrypt_passwd == p:
    28         print('login successful')
    29         return True
    30     else:
    31         print('password is wrong!')
    32         return False
    33 
    34 #根据name获取家目录路径
    35 def get_home_path(name):
    36     config = configparser.ConfigParser()
    37     path = os.path.dirname(os.path.abspath(__file__)) + os.sep + 'users.cfg'
    38     # print(path)
    39     config.read(path)
    40     # print(config.sections())
    41     if name not in config.sections():
    42         print('name is not exist')
    43         return None
    44     else:
    45         p = config.get(name,'home_path')
    46         new_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + os.sep +'db'+os.sep+p
    47         # print(new_path)
    48         return new_path
    49 
    50 def encrypt(str):
    51     '''
    52     对传入字符串进行加盐加密
    53     :param str: 需要进行加密的字符串
    54     :return: 返回加密过的字符串
    55     '''
    56     encrpt=hashlib.md5()
    57     encrpt.update(bytes('admin1234nnnnnn',encoding='utf-8'))
    58     encrpt.update(bytes(str,encoding='utf-8'))
    59     return encrpt.hexdigest()
    60 
    61 #计算文件的md5值
    62 def GetFileMd5(filename):
    63      if not os.path.isfile(filename):
    64          print('file is not exists')
    65          return
    66      myhash = hashlib.md5()
    67      with open(filename,'rb') as f:
    68          while True:
    69              b = f.read(8096)
    70              if not b :
    71                  break
    72              myhash.update(b)
    73          return myhash.hexdigest()
    74 
    75 # if __name__ == '__main__':
    76 #     a=GetFileMd5('users.cfg')
    77 #     print(a)
    common.py
    • 执行效果

    C:Python35python.exe C:/Users/dell/PycharmProjects/day7_2/bin2/客户端2.py
    username:alex
    password:123456
    login successful!
    >>:dir
    (458,)
     驱动器 C 中的卷没有标签。
     卷的序列号是 D48A-2DD8
    
     C:UsersdellPycharmProjectsday7_2dbalex 的目录
    
    2018/01/09  11:02    <DIR>          .
    2018/01/09  11:02    <DIR>          ..
    2018/01/05  17:18             5,231 aa.txt
    2018/01/09  11:02             5,231 bb.txt
    2018/01/08  16:46    <DIR>          ddd
    2018/01/05  14:43             8,815 test.py
                   3 个文件         19,277 字节
                   3 个目录 23,366,094,848 可用字节
    
    >>:rm bb.txt
    (61,)
    'rm' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    
    >>:del bb.txt
    (0,)
    
    >>:dir
    (414,)
     驱动器 C 中的卷没有标签。
     卷的序列号是 D48A-2DD8
    
     C:UsersdellPycharmProjectsday7_2dbalex 的目录
    
    2018/01/09  11:15    <DIR>          .
    2018/01/09  11:15    <DIR>          ..
    2018/01/05  17:18             5,231 aa.txt
    2018/01/08  16:46    <DIR>          ddd
    2018/01/05  14:43             8,815 test.py
                   2 个文件         14,046 字节
                   3 个目录 23,366,037,504 可用字节
    
    >>:put bb.txt
    >>:get aa.txt
    1024 5231
    1546 5231
    1605 5231
    1646 5231
    1698 5231
    1700 5231
    1752 5231
    1774 5231
    1817 5231
    1862 5231
    1903 5231
    1946 5231
    2026 5231
    2062 5231
    2152 5231
    2185 5231
    2211 5231
    2261 5231
    2297 5231
    2388 5231
    2423 5231
    2449 5231
    2485 5231
    2514 5231
    2535 5231
    2537 5231
    2562 5231
    2600 5231
    2647 5231
    2649 5231
    2673 5231
    2698 5231
    2723 5231
    2767 5231
    2787 5231
    2847 5231
    2961 5231
    3023 5231
    3065 5231
    3107 5231
    3150 5231
    3173 5231
    3221 5231
    3263 5231
    3309 5231
    3348 5231
    3384 5231
    3429 5231
    3477 5231
    3518 5231
    3558 5231
    3607 5231
    3634 5231
    3668 5231
    3709 5231
    3750 5231
    3765 5231
    3803 5231
    3837 5231
    3839 5231
    3863 5231
    3886 5231
    3911 5231
    3955 5231
    3975 5231
    4036 5231
    4083 5231
    4127 5231
    4142 5231
    4181 5231
    4201 5231
    4240 5231
    4292 5231
    4369 5231
    4482 5231
    4524 5231
    4559 5231
    4618 5231
    4685 5231
    4726 5231
    4815 5231
    4883 5231
    4902 5231
    4952 5231
    4989 5231
    5056 5231
    5084 5231
    5116 5231
    5118 5231
    5146 5231
    5181 5231
    5214 5231
    5227 5231
    5229 5231
    5231 5231
    file_path: C:UsersdellPycharmProjectsday7_2in2aa.txt
    文件传输成功
    >>:quit
    View Code

    定义了一个self.path参数,对用户的目录进行限定,以此做权限控制。

  • 相关阅读:
    关于清除浮动的最佳方法
    Bootstrap学习——栅格系统
    人工智能、机器学习和深度学习之间的区别与联系
    speech
    爬虫—启新宝接口函数
    爬虫—天眼查接口函数
    python链接mysql获得某列最大值
    获取指定路径下特定后缀的文件
    python读Excel
    DataTable 递归 简单的程序,来实现无限级列表 结合 jquery.table.js 实现
  • 原文地址:https://www.cnblogs.com/litzhiai/p/8250528.html
Copyright © 2020-2023  润新知