zoukankan      html  css  js  c++  java
  • 基于socketsever下实现的FTP

      1 # ### 客户端client
      2 import socket
      3 import json
      4 import struct
      5 import os
      6 
      7 sk = socket.socket()
      8 sk.connect( ("127.0.0.1" , 9000) )
      9 
     10 
     11 def myrecv(info_len = 1024,sign=False):
     12     # 要考虑黏包
     13     if sign:
     14         # (1) 先接受发送数据的实际长度
     15         info_len = sk.recv(4) # 1
     16         # unpack 返回的是元组(1999,)
     17         info_len = struct.unpack("i",info_len)[0] 
     18     
     19     # (2) 接受服务端返回的数据
     20     file_info = sk.recv(info_len).decode() # 2
     21     file_dic = json.loads(file_info)
     22     return file_dic
     23 
     24 
     25 
     26 # 处理收发数据的逻辑
     27 def auth(opt):
     28     """
     29     opt: login 登录 or register 注册
     30     """
     31     usr = input("username: ").strip()
     32     pwd = input("password: ").strip()
     33     dic = {"user":usr,"pwd":pwd,"operate":opt}
     34     str_dic = json.dumps(dic)
     35     # 把数据发送给服务端
     36     sk.send(str_dic.encode())
     37     return myrecv()
     38 
     39     
     40 # 1.注册
     41 # res = auth("register")
     42 # print(res)
     43 
     44 def register():
     45     res = auth("register")
     46     return res
     47     
     48 # 2.登录
     49 # res = auth("login")
     50 # print(res)
     51 def login():
     52     res = auth("login")
     53     return res
     54 
     55 # 3.退出
     56 def myexit():
     57     opt_dic = {"operate":"myexit"}
     58     sk.send(json.dumps(opt_dic).encode())
     59     exit("欢迎下次再来 ... ")
     60 # myexit()
     61 
     62 # 4.下载
     63 def download():
     64     operate_dict = {
     65     "operate":"download",
     66     "filename":"ceshivideo.mp4"
     67     }
     68     
     69     opt_str = json.dumps(operate_dict)
     70     sk.send(opt_str.encode("utf-8"))
     71     
     72     # (1) 为了避免黏包,接受两次数据
     73     res = myrecv(sign=True)
     74     print(res) # {'result': True, 'info': '改文件存在'}
     75     if res["result"]:
     76         # 创建文件夹
     77         try:
     78             os.mkdir("mydownload")
     79         except:
     80             pass
     81             
     82         # (2) 接受文件名字 和 文件大小
     83         dic = myrecv(sign=True)
     84         print(dic,"<2>") # {'filename': 'ceshivideo.mp4', 'filesize': 54822153} <2>
     85     
     86         # (3) 接受文件数据
     87         with open("./mydownload/" + dic["filename"],mode="wb") as fp:
     88             while dic["filesize"]:
     89                 content = sk.recv(1024)
     90                 fp.write(content)
     91                 dic["filesize"] -= len(content)
     92         print("客户端下载完毕")
     93     else:
     94         print("文件不存在")
     95     
     96     
     97     
     98 
     99 # 第一套界面
    100 operate_lst1 = [ ("登录",login) , ("注册",register) ,("退出",myexit)]
    101 # 第二套界面
    102 operate_lst2 = [("下载",download),("退出",myexit)]
    103 """
    104 ( 1, ('登录', <function login at 0x00000234890402F0>)   )
    105 (2, ('注册', <function register at 0x0000023489040268>))
    106 (3, ('退出', <function myexit at 0x0000023489040378>))
    107 """
    108 def main(operate_lst):
    109     for i,tup in enumerate(operate_lst,start=1):
    110         print(i,tup[0])
    111         
    112     num = int(input("请选择要执行的号码:>>>").strip()) 
    113     # 调用函数
    114     res = operate_lst[num-1][1]() # login()
    115     # 返回结果
    116     return res
    117 
    118 
    119 
    120 # 循环调用1号操作界面
    121 while True:
    122     # 开启第一套操作界面
    123     res = main(operate_lst1)
    124     print(res)
    125     # 开启第二套操作界面
    126     if res["result"]:
    127         while True:
    128             res = main(operate_lst2)
    129             print(res)
    130 
    131 sk.close()
      1 # ### 服务端   server
      2 import socketserver
      3 import json
      4 import os
      5 import hashlib
      6 import struct
      7 
      8 # print(os.getcwd())
      9 print(__file__)
     10 print(os.path.dirname(__file__))
     11 base_path = os.path.dirname(__file__)
     12 
     13 # 获取当前账户文件所在的完整绝对路径
     14 userinfo = os.path.join(base_path,"db","userinfo.txt")
     15 print(userinfo)
     16 """"""
     17 class Auth():
     18     
     19     @staticmethod
     20     def md5(usr,pwd):
     21         md5_obj = hashlib.md5(usr.encode())
     22         md5_obj.update(pwd.encode())
     23         return md5_obj.hexdigest()
     24 
     25     # 注册
     26     @classmethod
     27     def register(cls,opt_dic) :
     28         # opt_dic = {'user': 'lisi', 'pwd': '222', 'operate': 'register'}
     29         # 1.监测数据库当中是否存在该用户
     30         with open(userinfo,mode="r",encoding="utf-8") as fp:            
     31             for line in fp:
     32                 username = line.split(":")[0] 
     33                 if username == opt_dic["user"]:
     34                     return {"result":False,"info":"用户名已经存在了"}
     35                     
     36         # 2.当前这个用户允许注册
     37         with open(userinfo,mode="a+",encoding="utf-8") as fp:
     38             # 用户名:密码 换行
     39             fp.write("%s:%s
    " % (opt_dic["user"] , cls.md5(opt_dic["user"],opt_dic["pwd"])))
     40         
     41         """
     42             当用户上传文件的时候,动态给用户创建文件夹
     43         """
     44         
     45         # 3.直接返回对应的状态
     46         return {"result":True,"info":"注册成功"}
     47         
     48     # 登录
     49     @classmethod
     50     def login(cls,opt_dic):
     51         # opt_dic = {'user': 'lisi', 'pwd': '222', 'operate': 'register'}
     52         with open(userinfo,mode="r",encoding="utf-8") as fp:
     53             for line in fp:
     54                 username,password = line.strip().split(":")
     55                 if username == opt_dic["user"] and password == cls.md5(opt_dic["user"],opt_dic["pwd"]):
     56                     return {"result":True,"info":"登陆成功"}
     57             return {"result":False,"info":"登录失败"}
     58             
     59     # 退出
     60     @classmethod
     61     def myexit(cls,opt_dic):
     62         return {"result":"myexit"}
     63 
     64 class FTPServer(socketserver.BaseRequestHandler):
     65     def handle(self):
     66         while True:
     67             # 接受服务端发送过来的数据
     68             opt_dic = self.myrecv()
     69             print(opt_dic)
     70             
     71             # 判断类当中是否含有register这个方法,如果有就反射
     72             if hasattr(Auth,opt_dic["operate"]):
     73                 # getattr 反射出对应的register函数
     74                 res = getattr(Auth,opt_dic["operate"])(opt_dic)
     75                 
     76                 # 判断是myexit,代表退出
     77                 if res["result"] == "myexit":
     78                     return
     79                 
     80                 # 把返回值发送给客户端
     81                 self.mysend(res)
     82                 
     83                 # 等待处理用户第二套操作界面的逻辑
     84                 if res["result"]:
     85                     while True:
     86                         opt_dic = self.myrecv()
     87                         print(opt_dic)
     88                         
     89                         # 如果operate接受的是myexit 直接终止handle函数;
     90                         if opt_dic["operate"] == "myexit":
     91                             return                 
     92                         
     93                         # 可以反射 类 或者 对象 或者 模块响应的属性和方法
     94                         if hasattr(self,opt_dic["operate"]):
     95                             getattr(self,opt_dic["operate"])(opt_dic)
     96                 
     97                 
     98             # 如果Auth当中没有该操作的应急处理
     99             else:
    100                 dic = {"result":False,"info":"没有该操作"}
    101                 self.mysend(dic)
    102 
    103                 
    104             
    105         
    106     # 接受数据的方法
    107     def myrecv(self):
    108         info = self.request.recv(1024)
    109         opt_str = info.decode()
    110         opt_dic = json.loads(opt_str)
    111         return opt_dic
    112         
    113     # 发送数据的方法
    114     def mysend(self,send_info,sign=False):
    115         # 先把字典变成字符串,然后变成字节流发送出去
    116         send_info = json.dumps(send_info).encode()
    117         
    118         # 增加代码
    119         if sign:
    120             # 通过pack转化成居右固定4个字节长度的字节流
    121             res = struct.pack("i",len(send_info))
    122             # 把接下来要发送的数据长度发送给客户端
    123             self.request.send(res) # 1
    124         
    125         # 发送出去
    126         self.request.send(send_info) # 2
    127         
    128     # 下载方法
    129     def download(self,opt_dic):
    130         # {'operate': 'download', 'filename': 'ceshivideo.mp4'}
    131         # print(opt_dic)
    132         # 先判断是否存在该文件
    133         filename = opt_dic["filename"]
    134         file_abs = os.path.join(base_path,"myvideo",filename)
    135         # print(filename) # ceshivideo.mp4
    136         # print(file_abs) # D:/gongxiang8/day31/ftpmyvideoceshivideo.mp4
    137         
    138         if os.path.exists(file_abs):
    139             # 1.先告诉用户,可以操作,存在该文件
    140             dic = {"result":True,"info":"改文件存在"}
    141             self.mysend(dic,sign=True)
    142             
    143             # 2.把对应的文件名,以及文件的大小发过去
    144             filesize = os.path.getsize(file_abs)
    145             dic = {"filename":filename,"filesize":filesize}
    146             self.mysend(dic,sign=True)
    147             
    148             
    149             # 3.真正开始发送文件内容
    150             with open(file_abs,mode="rb") as fp:
    151                 while filesize:
    152                     # 一次性最多读取1024个字节
    153                     content = fp.read(1024)
    154                     self.request.send(content)
    155                     filesize -= len(content)
    156             print("服务器下载完毕")
    157             
    158         else:
    159             dic = {"result":False,"info":"改文件不存在"}
    160             self.mysend(dic,True)
    161         
    162         
    163         
    164         
    165         
    166         
    167         
    168 myserver = socketserver.ThreadingTCPServer( ("127.0.0.1" , 9000)  , FTPServer)
    169 # 让一个端口绑定多个程序(测试时使用)
    170 socketserver.TCPServer.allow_reuse_address = True
    171 myserver.serve_forever()
  • 相关阅读:
    BZOJ 2957: 楼房重建
    那些年犯下的逗比错误
    BZOJ 2165: 大楼
    BZOJ 2115: [Wc2011] Xor
    bzoj 2006 [NOI2010]超级钢琴——ST表+堆
    bzoj 4571 [Scoi2016]美味——主席树
    bzoj 1014 [JSOI2008]火星人prefix——splay+哈希
    bzoj 2962 序列操作——线段树(卷积?)
    CF 809D Hitchhiking in the Baltic States——splay+dp
    bzoj 3489 A simple rmq problem——主席树套线段树
  • 原文地址:https://www.cnblogs.com/zyling/p/11938225.html
Copyright © 2011-2022 走看看