SELECT版FTP:使用SELECT或SELECTORS模塊實現併發簡單版FTP允許多用戶併發上傳下載文件 必須使用select or selectors模塊支持多併發,禁止使用多線程或多進程 REDMAE 1 #!usr/bin/env python 2 #-*-coding:utf-8-*- ...
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#客戶端啟動
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 client.send(json.dumps(data_header).encode())#用json 序列化後,發送相關 信息 65 66 print("文件[%s]發送中...."%data_header["filename"]) 67 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 datas=client.recv(4096)#接收數據 指令 93 data_l= json.loads(datas.decode())#反序列 94 # print(data_l) 95 # print(data_l['size']) 96 if data_l['filename']==False: 97 print('\033[41;1m文件不存在或者出錯\033[0m') 98 continue 99 prten=show_process(data_l["size"]) 100 prten.__next__() 101 file_dir=config.USER_DIR+'/'+data_l["filename"] 102 file_obj=open(file_dir,'wb')#打開新建 這個文件 103 rece_size=0#定義 文件大小值 104 105 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 datas=client.recv(4096)#接收數據 指令 127 data_l= json.loads(datas.decode())#反序列 128 for k,v in enumerate(data_l): 129 print('編號: %s 文件名:%s'%(k,v)) 130 131 else: 132 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=9500View 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_sView 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版)
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(0)#也設成非阻塞 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版)
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(False)#設成非阻塞 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('接收的數據:') 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 if data['action']=="put":#如果接收的字典中是put,就是進行接收 43 #serv=socket_server(data,conn) 44 serv.put_file(serv.open_f())#調對象方法 45 elif data['action']=='get':#下載 46 #serv=socket_server(data,conn)#實例化 47 serv.send_file(serv.open_f())#調 用方法 48 elif data['action']=='ls':#查看 49 #serv=socket_server(data,conn) 50 serv.ls_file(serv.open_f()) 51 return 52 else:#如果為空 53 print('closing', conn) 54 sel.unregister(conn)#取消註冊 55 conn.close()#關閉連接 56 57 server_addr=('0.0.0.0',9501)#設置綁定的 IP 埠 58 s=socket.socket()#定義 59 s.bind(server_addr)#綁定IP 埠 60 s.listen(5)#對列5 61 s.setblocking(False)#非阻塞 62 print('正在監聽中') 63 64 sel = selectors.DefaultSelector()#生成一個創建一個selectors對象 65 sel.register(s, selectors.EVENT_READ, accept)#註冊連接 返調函數為accepts 66 67 while True: 68 events = sel.select()#預設為阻塞模式 69 for key, mask in events:#如果有連接,接入 70 callback = key.data#新建連接句柄 71 callback(key.fileobj, mask)View Code
| |- - -cfg/#