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('\033[41;1m文件为空!,不能上传\033[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('\033[41;1m该文件不存在或为目录\033[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('\033[41;1m文件不存在或者出错\033[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('\033[41;1m用户名或密码错误\033[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

 

 




posted @ 2017-06-25 19:31  莫柔落切  阅读(542)  评论(1编辑  收藏  举报