zoukankan      html  css  js  c++  java
  • python第五十四天--第十周作业

    SELECT版FTP:
    使用SELECT或SELECTORS模块实现并发简单版FTP
    允许多用户并发上传下载文件

    必须使用select or selectors模块支持多并发,禁止使用多线程或多进程

    REDMAE

    用户登陆

    1、查看共享目录文件
    2、上传文件,
    3、下载方件
    4、退出

    程序结构:
    socket_server_client/#程序目录
    |- - -clients/#client程序主目录
    | |- - -__init__.py
    | |- - -bin/#启用目录
    | | |- - - __init__.py
    | | |- - -socket_client.py#客户端启动
    | |
    | |- - -cfg/#配置文件目录
    | | |- - - __init__.py
    | | |- - -config.py#配置文件
    | |
    | |- - -core/#主要程序目录
    | | |- - - __init__.py
    | | |- - -client_func.py#主要函数
    | |
    | |- - -home/#客户端下载文件目录
    |
    |- - -servers/#server程序主目录
    | |- - -__init__.py
    | |- - -bin/#启用目录
    | | |- - - __init__.py
    | | |- - -registration.py#用户注册
    | | |- - -server.py#服务端启动(selectors版)
    | | |- - -socket_server.py#服务端启动(select版)

    | |
    | |- - -cfg/#配置文件目录
    | | |- - - __init__.py
    | | |- - -config.py#配置文件
    | |
    | |- - -core/#主要程序目录
    | | |- - - __init__.py
    | | |- - -server_classc.py#主要函数
    | |
    | |- - -db/#用户上传文件主目录
    | |- - -user_file/#用户上传目录(共享)
    | |- - -user_names#注册用户文件
    |

    程序结构:
    socket_server_client/#程序目录
    |- - -clients/#client程序主目录
    | |- - -__init__.py
    | |- - -bin/#启用目录
    | | |- - - __init__.py
    | | |- - -socket_client.py#客户端启动
    (2016/06/26修改,去收发大文件异常)

      1 #!usr/bin/env python
      2 #-*-coding:utf-8-*-
      3 # Author calmyan
      4 
      5 import socket,os,json,sys
      6 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#获取相对路径转为绝对路径赋于变量
      7 sys.path.append(BASE_DIR)#增加环境变量
      8 from core.client_func import user_pwd
      9 #from core.client_func import show_process
     10 from cfg import config
     11 
     12 #进度条
     13 def show_process(lens):
     14     received_size=0#定义大小
     15     current_percent=0#当前大小百分比
     16     while received_size<lens:
     17         if int((received_size/lens)*100)>current_percent:
     18             print('#',end='',flush=True)
     19             current_percent=int((received_size/lens)*100)
     20         new_size=yield
     21         received_size+=new_size
     22 
     23 server_addr=('localhost',9500)#设置绑定的 IP 端口
     24 #server_addr=('192.168.11.50',9500)#设置绑定的 IP 端口
     25 client=socket.socket()
     26 client.connect(server_addr)
     27 while True:
     28     data_d=user_pwd(client)
     29     if data_d['tag']:#运行#用户名登陆成功
     30         while True:
     31             print('''=====指令提示====
     32             查看目录文件: ls
     33             下载文件: get 文件名 或 文件编号  如: get test.txt  或  get 1
     34             上传方件: put 路径/文件名 如 put e:/test.txt
     35             退出:exit
     36             ''')
     37             cho=input('指令 >>:').strip()
     38             if len(cho)==0:continue
     39             if cho=='exit':exit()#退出指令
     40             cmd_list=cho.split()
     41             if cmd_list[0]=='put':#如果等于下载指令
     42                 if len(cmd_list)==1:
     43                     print('没有输入相关文件名')
     44                     continue
     45                 filename=cmd_list[1]
     46                 file_dir=config.USER_DIR+'/'+filename
     47                 if os.path.isfile(file_dir):#如果文件存在
     48                     file_obj=open(file_dir,"rb")#打开文件
     49                     name=file_obj.name.split('/')[-1]#文件名
     50                     #name=filename.split("\")[-1]#文件名
     51                     sez=os.path.getsize(file_dir)#获取文件大小
     52                     if sez<1:
     53                         print('33[41;1m文件为空!,不能上传33[0m')
     54                         continue
     55                     progress = show_process(sez) #进度条 传入文件大小
     56                     progress.__next__()
     57                     rat=0
     58                     file_obj.seek(rat)#移动到位置
     59                     data_header={
     60                         "action":"put",
     61                         "filename":name,
     62                         "size":sez
     63                     }
     64 
     65                     client.send(json.dumps(data_header).encode())#用json 序列化后,发送相关 信息
     66                     attr=client.recv(100)
     67                     print("文件[%s]发送中...."%data_header["filename"])
     68                     while rat<sez:
     69                         line=file_obj.read(4096)
     70                         client.send(line)
     71                         try:
     72                             progress.send(len(line))#传入当前数据大小
     73                         except StopIteration as e:
     74                             print("100%")
     75                             break
     76                     print("文件[%s]发送完毕!"%data_header["filename"])
     77                 else:
     78                     print('33[41;1m该文件不存在或为目录33[0m')
     79                     continue
     80             elif cmd_list[0]=='get':#如果等于get 上传指令
     81                 if len(cmd_list)==1:
     82                     print('没有输入相关文件名')
     83                     continue
     84                 filename=cmd_list[1]
     85                 print(filename)
     86                 data_header={
     87                         "action":"get",
     88                         "filename":filename,
     89                         "size":''
     90                     }
     91                 client.send(json.dumps(data_header).encode())#用json 序列化后,发送相关 信息
     92 
     93                 datas=client.recv(4096)#接收数据 指令
     94                 data_l= json.loads(datas.decode())#反序列
     95                 # print(data_l)
     96                 # print(data_l['size'])
     97                 if data_l['filename']==False:
     98                     print('33[41;1m文件不存在或者出错33[0m')
     99                     continue
    100                 client.send('为了防粘包'.encode('utf-8'))#防粘包
    101                 prten=show_process(data_l["size"])
    102                 prten.__next__()
    103                 file_dir=config.USER_DIR+'/'+data_l["filename"]
    104                 file_obj=open(file_dir,'wb')#打开新建 这个文件
    105                 rece_size=0#定义 文件大小值
    106                 while rece_size<data_l["size"]:#小于接收的文件大小时,
    107                     recv_data=client.recv(4096)
    108                     file_obj.write(recv_data)#写入文件
    109                     rece_size+=len(recv_data)#增加文件大小计算
    110                     try:
    111                         prten.send(len(recv_data))
    112                     except StopIteration as e:
    113                         print('100%')
    114 
    115                 else:
    116                     print("文件[%s]接收完毕!"%data_l["filename"])
    117                     file_obj.flush()
    118                     file_obj.close()#关闭文件
    119             elif cmd_list[0]=='ls':#查看目录文件
    120                 data_header={
    121                         "action":"ls",
    122                         "filename":'',
    123                         "size":''
    124                     }
    125                 client.send(json.dumps(data_header).encode())#用json 序列化后,发送相关 信息
    126                 client.recv(100)#防粘包
    127                 #client.send('为了防粘包'.encode('utf-8'))#防粘包
    128                 datas=client.recv(4096)#接收数据 指令
    129                 data_l= json.loads(datas.decode())#反序列
    130                 for k,v in enumerate(data_l):
    131                     print('编号: %s  文件名:%s'%(k,v))
    132 
    133     else:
    134         print(data_d['mag'])
    View Code


    | |- - -cfg/#配置文件目录
    | | |- - - __init__.py
    | | |- - -config.py#配置文件

     1 #!usr/bin/env python
     2 #-*-coding:utf-8-*-
     3 # Author calmyan
     4 
     5 import os ,sys
     6 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#获取相对路径转为绝对路径赋于变量
     7 sys.path.append(BASE_DIR)#增加环境变量
     8 
     9 
    10 USER_DIR=BASE_DIR+'/home'#定义用户目录文件路径变量
    11 IP='192.168.11.50'
    12 PORST=9500
    View Code
    |      |- - -core/#主要程序目录
    | | |- - - __init__.py
    | | |- - -client_func.py#主要函数
     1 #!usr/bin/env python
     2 #-*-coding:utf-8-*-
     3 # Author calmyan
     4 import socket,os,json,sys
     5 #用户名登陆函数
     6 def user_pwd(client):
     7     user_=input('请输入用户名:').strip()
     8     pwd_=input('请输入密码:').strip()
     9     data_header={
    10                 "action":"user",
    11                 "name":user_,
    12                 "pwd":pwd_
    13             }
    14     client.send(json.dumps(data_header).encode())#用json 序列化后,发送相关 信息
    15     data=client.recv(4096)#接收数据 指令
    16     data_s=json.loads(data.decode('utf-8'))#反序列
    17     return data_s
    View Code
    |- - -servers/#server程序主目录
    | |- - -__init__.py
    | |- - -bin/#启用目录
    | | |- - - __init__.py
    | | |- - -registration.py#用户注册
     1 #!usr/bin/env python
     2 #-*-coding:utf-8-*-
     3 # Author calmyan
     4 import socket,os,json,sys,pickle
     5 
     6 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#获取相对路径转为绝对路径赋于变量
     7 sys.path.append(BASE_DIR)#增加环境变量
     8 from cfg import config
     9 print('用户注册'.center(60,'='))
    10 while True:
    11     user_=input('请输入您要注册的用户名:').strip()
    12     user_dir=os.path.join(config.USER_DIR,user_)#拼接用户目录路径
    13     if os.path.isdir(user_dir):# 判断一个目录是否存在
    14         print('用户已经存在请重输!')
    15         continue
    16     else:
    17         pwd_=input('请输入密码:').strip()
    18         pwd_two=input('请确认密码:').strip()
    19         if pwd_==pwd_two:
    20 
    21 
    22             if  not os.path.isfile(config.USER_FILE):
    23                 with open(config.USER_FILE,'w',encoding='utf-8') as f:
    24                     f.write('{}')
    25             with open(config.USER_FILE,'r+',encoding='utf-8') as f:
    26                 data=eval(f.readline())
    27                 data[user_]=pwd_
    28                 f.seek(0)
    29                 f.write(str(data))
    30             print('用户[%s]注册成功!'%user_)
    31             exit()
    View Code
    |      |       |- - -server.py#服务端启动(selectors版)(2016/06/26修改,去收发大文件异常)
     1 #!usr/bin/env python
     2 #-*-coding:utf-8-*-
     3 # Author calmyan 
     4 #python 
     5 #2017/6/24    19:34
     6 #__author__='Administrator'
     7 import select,socket,sys ,queue,json,os
     8 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#获取相对路径转为绝对路径赋于变量
     9 sys.path.append(BASE_DIR)#增加环境变量
    10 
    11 import core
    12 from core.server_class import socket_server
    13 
    14 s=socket.socket()#实例化一个连接对象
    15 s.setblocking(0)#设置成非阻塞
    16 server_addr=('localhost',9500)#设置绑定的 IP 端口
    17 s.bind(server_addr)#连接对象绑定IP 端口
    18 s.listen(100)#队列  可连接数量
    19 inputs=[s,]#首先要监测本身
    20 
    21 outputs=[]#发送列表
    22 
    23 meg_queues={} #发送 连接对象的队列集合  字典
    24 
    25 while True:
    26     print('监听中......')
    27     readable,writeable,exeptional=select.select(inputs,outputs,inputs)#生成select 对象,返回三个列表 连接,发关,错误
    28 
    29     for i in readable: #i为一个socket
    30         if i is s:#如果i 是s 表示有新 连接 进来
    31             conn,client_addr=i.accept()#建立一个新连接
    32             print('接入一个新连接...',client_addr)
    33             conn.setblocking(1)#设成 阻塞
    34             inputs.append(conn)#加入select,的连接列表,避免出现阻塞
    35             meg_queues[conn]=queue.Queue()#创建一个队列  添加到字典
    36         else:
    37             try:
    38                 data=i.recv(1024)#如果不是新连接就收数据
    39             except Exception as e:
    40                 print(e)
    41             if data: #如果数据不为空
    42                 print('[%s] 发来的数据 [%s]'%(i.getpeername,data))
    43                 meg_queues[i].put(data)#当前连接的消息队列加入数据
    44                 if i not in outputs:#如果当前连接没有在发送列表内,就加入发送列表
    45                     outputs.append(i)
    46             else:
    47                 print('客户端已经断开了....')#开始清理工作
    48                 if i in outputs:#在发送列表
    49                     outputs.remove(i)#在发送列表内删除
    50                 inputs.remove(i)#在连接列表内删除
    51                 del meg_queues[i]#在队列字典内删除
    52 
    53     for w in writeable:#循环发送列表
    54         try:
    55             msg=meg_queues[w].get_nowait()#取出队列中的数据,判断
    56         except queue.Empty:#如果数据为空
    57             outputs.remove(w)##从发送列表内删除
    58         else:
    59             data = json.loads(msg.decode())#反序列
    60             serv=socket_server(data,w)
    61             if data['action']=='user':#如果是用户名,进行认证
    62                 #serv=socket_server(data,conn)
    63                 ret=serv.ret_l()
    64                 if ret['tag']:
    65                     pass
    66                 else:
    67                     break
    68             #print('echoing', repr(data), 'to', conn)
    69             #data=json.loads(data)
    70             if data['action']=="put":#如果接收的字典中是put,就是进行接收
    71                 #serv=socket_server(data,conn)
    72                 serv.put_file(serv.open_f())#调对象方法
    73             elif data['action']=='get':#下载
    74                 #serv=socket_server(data,conn)#实例化
    75                 serv.send_file(serv.open_f())#调 用方法
    76             elif data['action']=='ls':#查看
    77                 #serv=socket_server(data,conn)
    78                 serv.ls_file(serv.open_f())
    79                 break
    80 
    81             #w.send(msg)#发送
    82 
    83 
    84 
    85     for e in exeptional:#循环错误列表
    86         print('连接[%s]出错!'%e.getpeername)
    87         inputs.remove(e)##从发送列表内删除
    88         if e in outputs:#在发送列表
    89             outputs.remove(e)#在发送列表内删除
    90         e.close()
    91         del meg_queues[e]#在队列字典内删除
    View Code

    | | |- - -socket_server.py#服务端启动(select版)(2016/06/26修改,去收发大文件异常)

     1 #!usr/bin/env python
     2 #-*-coding:utf-8-*-
     3 # Author calmyan
     4 import socket,os,json
     5 import sys
     6 import selectors
     7 
     8 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#获取相对路径转为绝对路径赋于变量
     9 sys.path.append(BASE_DIR)#增加环境变量
    10 
    11 from  core.server_class import socket_server
    12 from  core.server_class import open_file_list
    13 
    14 
    15 
    16 
    17 
    18 def accept(sock, mask):
    19     conn, addr = sock.accept()  # 建立新连接
    20     print('accepted', conn, 'from', addr)
    21     conn.setblocking(1)#设成非阻塞
    22     sel.register(conn, selectors.EVENT_READ, read)#注册 连接,回调函数 read
    23 
    24 
    25 def read(conn,mask):
    26     #gevent.spawn(handle_request, cli)#创建一个新协程来
    27     data = conn.recv(1024)  # 接收数据
    28     if data:#不为空
    29         print('接收的数据:',data)
    30         #print(mask)
    31         if len(data)==0:
    32             return
    33         data = json.loads(data.decode())#反序列
    34         serv=socket_server(data,conn)
    35         if data['action']=='user':#如果是用户名,进行认证
    36             #serv=socket_server(data,conn)
    37             ret=serv.ret_l()
    38             if ret['tag']:
    39                 pass
    40             else:
    41                 return
    42         elif data['action']=="put":#如果接收的字典中是put,就是进行接收
    43             #serv=socket_server(data,conn)
    44             serv.put_file(serv.open_f())#调对象方法
    45             return
    46         elif data['action']=='get':#下载
    47             #serv=socket_server(data,conn)#实例化
    48             serv.send_file(serv.open_f())#调 用方法
    49             return
    50         elif data['action']=='ls':#查看
    51             #serv=socket_server(data,conn)
    52             serv.ls_file(serv.open_f())
    53             return
    54         else:
    55             return
    56     else:#如果为空
    57         print('closing', conn)
    58         sel.unregister(conn)#取消注册
    59         conn.close()#关闭连接
    60 
    61 server_addr=('0.0.0.0',9500)#设置绑定的 IP 端口
    62 s=socket.socket()#定义
    63 s.bind(server_addr)#绑定IP 端口
    64 s.listen(5)#对列5
    65 s.setblocking(False)#非阻塞
    66 print('正在监听中')
    67 
    68 sel = selectors.DefaultSelector()#生成一个创建一个selectors对象
    69 sel.register(s, selectors.EVENT_READ, accept)#注册连接  返调函数为accepts
    70 
    71 while True:
    72         events = sel.select()#默认为阻塞模式
    73         for key, mask in events:#如果有连接,接入
    74             callback = key.data#新建连接句柄
    75             callback(key.fileobj, mask)
    View Code

    | |- - -cfg/#配置文件目录
    |      |       |- - - __init__.py
    | | |- - -config.py#配置文件

     1 #!usr/bin/env python
     2 #-*-coding:utf-8-*-
     3 # Author calmyan
     4 import os ,sys
     5 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#获取相对路径转为绝对路径赋于变量
     6 sys.path.append(BASE_DIR)#增加环境变量
     7 
     8 
     9 USER_DIR=BASE_DIR+'/db/user_file/'#定义用户目录文件路径变量
    10 
    11 USER_FILE=BASE_DIR+'/db/user_names'#定义用户名密码文件路径变量
    12 IP='localhost'
    13 PORST=9501
    View Code
    |      |- - -core/#主要程序目录
    | | |- - - __init__.py
    | | |- - -server_classc.py#主要函数(2016/06/26修改,去收发大文件异常)
      1 #!usr/bin/env python
      2 #-*-coding:utf-8-*-
      3 # Author calmyan
      4 import socket,os,json,sys,pickle
      5 import selectors
      6 
      7 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#获取相对路径转为绝对路径赋于变量
      8 sys.path.append(BASE_DIR)#增加环境变量
      9 
     10 from cfg import config
     11 
     12 
     13 #用户名检测函数
     14 
     15 def open_file_list(name,pas):#传入当前类
     16     with open(config.USER_FILE,'r',encoding='utf-8') as f:
     17         data=eval(f.readline())
     18         print(data)
     19         if name in data and pas==data[name]:
     20             return True
     21         else:
     22             return False
     23 
     24 
     25 
     26 
     27 #连接类
     28 class socket_server(object):
     29     '''连接类'''
     30     file_path=config.USER_DIR#用户路经变量
     31     def __init__(self,data,conn):#传入
     32         self.DATA=data
     33         self.conn=conn
     34 
     35 
     36     def ret_l(self):
     37         self.ret=self.login(self.DATA["name"],self.DATA['pwd'],self.conn)#用户名检测
     38         return self.ret
     39     def open_f(self):#打开目录
     40 
     41         file_dir=os.path.join(config.USER_DIR)#用户目录
     42         print(file_dir)
     43         file_name=os.listdir(file_dir)#目录文件列表
     44         f=file_dir+'/'+self.DATA['filename']##上传的文件名
     45         return file_dir,file_name,f#返回
     46 
     47     def ls_file(self,data):#查看文件
     48         self.conn.send('为了防粘包'.encode('utf-8'))#防粘包
     49         #self.conn.recv(100)
     50         self.conn.send(json.dumps(data[1]).encode())
     51         return
     52 
     53     def send_file(self,data):
     54 
     55         if self.DATA['filename'] in data[1]:#如果是输入文件名
     56             f=data[0]+'/'+self.DATA['filename']
     57             file_obj=open(f,"rb")#打开文件
     58             name=file_obj.name.split('/')[-1]#文件名
     59             sez=os.path.getsize(f)#获取文件大小
     60 
     61             if sez<1:
     62                 print('文件错误!')
     63                 self.DATA['filename']=False
     64                 self.conn.send(json.dumps(self.DATA).encode())
     65                 return
     66             print(''.center(30,'='))
     67             print(sez)
     68             print(''.center(30,'='))
     69             data_header={
     70                     "action":"put",
     71                     "filename":name,
     72                     "size":sez
     73                     }
     74             #self.conn.send(b'1')
     75             self.conn.send(json.dumps(data_header).encode())#用json 序列化后,发送相关 信息
     76             self.conn.recv(100)
     77             file_siez=0
     78             while file_siez<sez:
     79             #for line in file_obj:
     80                 line=file_obj.read(1024)
     81                 file_siez+=len(line)
     82                 self.conn.send(line)#发送数据
     83 
     84         elif self.DATA['filename'].isdigit():#如果是输入编号
     85             num=int(self.DATA['filename'])#转为数字
     86             try:
     87                 f=data[0]+'/'+data[1][num]#
     88                 file_obj=open(f,"rb")#打开文件
     89                 name=file_obj.name.split('/')[-1]#文件名
     90                 sez=os.path.getsize(f)#获取文件大小
     91                 if sez<1:
     92                     print('文件错误!')
     93                     self.DATA={'filename':False}
     94                     self.conn.send(json.dumps(self.DATA).encode())
     95                     return
     96                 print(sez)
     97                 data_header={
     98                 "action":"put",
     99                 "filename":name,
    100                 "size":sez
    101                 }
    102                 self.conn.send(json.dumps(data_header).encode())#用json 序列化后,发送相关 信息
    103                 self.conn.recv(100)
    104                 for line in file_obj:
    105                     self.conn.send(line)#发送数据
    106                 #self.conn.send(json.dumps(f).encode())#发送文件
    107             except Exception as e:
    108                 self.DATA={'filename':False}
    109                 self.conn.send(json.dumps(self.DATA).encode())
    110                 return
    111         else:
    112             data={'filename':False}
    113             self.conn.send(json.dumps(data).encode())
    114             return
    115     def put_file(self,data):#上传文件
    116         file_obj=open(data[2],'wb')#打开新建 这个文件
    117         rece_size=0#定义 文件大小值
    118         self.conn.send('为了防粘包'.encode('utf-8'))#防粘包
    119         while rece_size<self.DATA["size"]:#小于接收的文件大小时,
    120             recv_data=self.conn.recv(4096)
    121             file_obj.write(recv_data)#写入文件
    122             rece_size+=len(recv_data)#增加文件大小计算
    123         else:
    124             print("文件[%s]接收完毕!"%self.DATA["filename"])
    125             file_obj.flush()
    126             file_obj.close()#关闭文件
    127             return
    128     #@staticmethod
    129     def login(self,name,pas,conn):#用户检测 函数
    130         try:
    131             if open_file_list(name,pas):
    132                 tag=True
    133                 error=''
    134                 datas={'user':name}
    135                 data={'mag':'用户认证通过','tag':True}
    136                 print(json.dumps(data).encode())
    137                 conn.send(json.dumps(data).encode())
    138             else:
    139                 raise Exception('33[41;1m用户名或密码错误33[0m' %name)
    140         except Exception as e:
    141             tag=False
    142             error=str(e)
    143             datas=''
    144             data={'mag':'用户或密码错误','tag':False}
    145             print('发送数据%s'%data)
    146             conn.send(json.dumps(data).encode())
    147         return {'tag':tag,'error':error,'data':datas}
    View Code
     




  • 相关阅读:
    习题3.2三角形的知识1
    习题3.1三角形的知识2
    复习3.1三角形的知识1
    斜边和直角边公理、角的平分线11
    三角形全等的判定10
    全等三角形9
    你不知道的javascript(中卷)----读书笔记
    jquery----抽奖系统
    jQuery-----五子棋
    个人练手仿站
  • 原文地址:https://www.cnblogs.com/uge3/p/7077632.html
Copyright © 2011-2022 走看看