前些日子写了一个网络编程的,纯新手,能优化的地方很多!但是,也算自己独立完成了这么一个东西,晚上发上来!!
socket_project
项目结构:
│ readme
│ 原理图.png
│
├─.idea
│ │ misc.xml
│ │ modules.xml
│ │ workspace.xml
│ │ 网络编程.iml
│ │
│ └─inspectionProfiles
├─client
│ ├─bin
│ │ start.py
│ │
│ ├─conf_c
│ │ │ info_c.py
│ │ │
│ │ └─__pycache__
│ │ info_c.cpython-35.pyc
│ │
│ ├─core
│ │ │ main.py
│ │ │
│ │ └─__pycache__
│ │ main.cpython-35.pyc
│ │
│ └─file_position
└─server
├─bin
│ start.py
│
├─conf
│ │ info.py
│ │ __init__.py
│ │
│ └─__pycache__
│ info.cpython-35.pyc
│ __init__.cpython-35.py
│
├─core
│ │ main.py
│ │
│ └─__pycache__
│ main.cpython-35.pyc
│
├─file_position
│ │ 1.mp4
│ │
│ └─ncp
└─user_db
auth_file
README
功能: 用户加密认证 每个用户有自己的家目录,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp server上随意切换目录 允许用户查看当前目录下的文件 允许上传和下载文件,并保证文件的一致性 文件传输过程中显示进度条 附加:支持文件的断点续传 开发的程序需符合PEP8开发规范,及专业的生产软件设计规范,包括目录、代码命名、功能接口等 user_dic = {'ncp':'123123','cpp':'321321','tesla':'222222'} 测试用的两个文件,一个视频文件放在服务端的共享目录:file_position,测试文件在客户端的file_position的ncp下,一个文件小于20M一个大于 用户磁盘配额说明:total_package = {'ncp':count_size(20),'cpp':count_size(10),'tesla':count_size(50)} ncp:20M cpp:10M tesla:50M 1.用户密码通过hash的md5算法加密 2.这里没有采用多线程或者多进程,后期可加 3.用户有自己的家目录,用ls查看自己家目录下的文件 4.用户可以用cd path完成路径切换,path为你要切换的目录(注意,如果cd后不加空格就输入会报错) 5.磁盘配完成 6.用户可以上传、下载并且包头用了md5随机加密,每次操作md5不一样 6.能显示进度条,client使用get下载文件时,并且可以断定续传,原理相同,没有在put上实现 7.自己强化的功能就是client可以使用大部分DOS命令对服务端进行操作
#author:nie cheng ping # _*_ coding=gbk _*_ from client.conf_c import info_c import hashlib import socket import struct import json import os import sys import math import time class FTPclient: socket_net = info_c.socket_net socket_type = info_c.socket_type package_recv = info_c.package_size str_code = info_c.coding file_path = info_c.file_path_c def __init__(self,server_ip_port,connection=True): self.socket = socket.socket(self.socket_net,self.socket_type) self.server_ip_port = server_ip_port if connection: self.connection() else: self.close_line() def connection(self): self.socket.connect(self.server_ip_port) print(self.server_ip_port) def close_line(self): self.socket.close() def progress(self, recvd, total): fraction = '{:.0%}'.format(recvd / total) sys.stdout.write(' [%-30s] %s' % ('#' * int(math.floor(recvd * 30 / total)),fraction)) sys.stdout.flush() if recvd == total: sys.stdout.write(' ') def run_commands(self,inp): if not inp: return header = self.socket.recv(4) header_json_len = struct.unpack('i',header)[0] header_json = json.loads(self.socket.recv(header_json_len).decode(self.str_code)) data_len = header_json['package_size'] recv_data = b'' recv_size = 0 while recv_size < data_len: recv_data += self.socket.recv(self.package_recv) recv_size += self.package_recv print(recv_data.decode(self.str_code)) return def get(self,user): header = self.socket.recv(4) # 接收报头长度 print(header) header_json_len = struct.unpack('i',header)[0] # 根据报头长度拆分报头 # 获取报头中的报头信息 header_bytes = self.socket.recv(header_json_len) header_bytes_json = header_bytes.decode(self.str_code) # decode得到报文头内容,再反序列化 header_json_dic = json.loads(header_bytes_json) print(header_json_dic) data_len = header_json_dic['file_size'] # data_len 等于总的数据长度 share_file = os.path.join(self.file_path,user,header_json_dic['filename']) if os.path.exists(share_file): with open(share_file,'rb')as f: data = f.read() # data 等于断后现有的数据大小 if len(data) < data_len: recv_size = 0 while recv_size < len(data): recv_data = self.socket.recv(self.package_recv) recv_size += len(recv_data) self.progress(recv_size,len(data)) with open(share_file,'ab+')as f: f.seek(len(data)) recv_data = b'' recv_size = len(data) while recv_size < data_len: recv_data = self.socket.recv(self.package_recv) recv_size += len(recv_data) f.write(recv_data) self.progress(recv_size,data_len) return with open(share_file,'wb')as f: recv_size = 0 while recv_size < data_len: recv_data = self.socket.recv(self.package_recv) f.write(recv_data) recv_size += len(recv_data) self.progress(recv_size,data_len) def put(self,inp,user,header): cmd = inp.split() share_file = os.path.join(self.file_path,user,cmd[1]) send_size = 0 with open(share_file,'rb')as f: for i in f: self.socket.send(i) send_size += len(i) self.progress(send_size,header['file_size']) else: print('send ok') def summary(self): while True: hash_data = hashlib.md5() data_user = self.socket.recv(self.package_recv) print(data_user.decode(self.str_code)) inp_user = input('>>') self.socket.send(inp_user.encode(self.str_code)) data_pass = self.socket.recv(self.package_recv) print(data_pass.decode(self.str_code)) inp_password = input('>>') hash_data.update(inp_password.encode(self.str_code)) self.socket.send(hash_data.hexdigest().encode(self.str_code)) data_recv = self.socket.recv(self.package_recv) if data_recv.decode(self.str_code) == 'ok': user_file_dir = os.path.join(self.file_path,inp_user) if not os.path.exists(user_file_dir): os.mkdir(user_file_dir) while True: inp = input('>>') if not inp: continue cmd = inp.split() while True: if cmd[0] == 'get': self.socket.send(inp.encode(self.str_code)) self.get(inp_user) # 上次要设置用户在server端的磁盘大小空间,所以验证全在这里 elif cmd[0] == 'put': share_file = os.path.join(self.file_path, inp_user, cmd[1]) if not os.path.exists(share_file): print('file is not found') break self.socket.send(inp.encode(self.str_code)) header = {'filename': share_file, 'file_size': os.path.getsize(share_file), 'md5': info_c.hash_data.hexdigest()} header_json = json.dumps(header) header_json_bytes = header_json.encode(self.str_code) header_struct = struct.pack('i', len(header_json_bytes)) self.socket.send(header_struct) self.socket.send(header_json_bytes) data = self.socket.recv(self.package_recv) if data.decode(self.str_code) == 'ok': self.put(inp,inp_user,header) else: print(data.decode(self.str_code)) break else: self.socket.send(inp.encode(self.str_code)) self.run_commands(inp) break if data_recv.decode(self.str_code) == 'authentication is false': print(data_recv.decode(self.str_code)) continue
#author:nie cheng ping # _*_ coding=gbk _*_ import os import socket import hashlib import json import random import string ftp_path = 'file_position' user_db_file = 'user_db' auth_name = 'auth_file' base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) user_db_path = os.path.join(base_dir,user_db_file) auth_file = os.path.join(user_db_path,auth_name) ftp_s_home = os.path.join(base_dir,ftp_path) package_size = 4096 socket_net = socket.AF_INET socket_type = socket.SOCK_STREAM listen_line = 5 coding = 'gbk' md5_data = ''.join(random.sample(string.digits,6)) hash_data = hashlib.md5() hash_data.update(md5_data.encode(coding)) def count_size(number): number_bytes = number*1024*1024 return number_bytes total_package = {'ncp':count_size(20),'cpp':count_size(10),'tesla':count_size(50)} def create_auth(): user_name = ('ncp','cpp','tesla') user_dic = {'ncp':'123123','cpp':'321321','tesla':'222222'} hash_data = hashlib.md5() hash_list = [] for i in user_name: hash_data.update(user_dic[i].encode('gbk')) hash_list.append(hash_data.hexdigest()) user_auth = {'ncp':hash_list[0],'cpp':hash_list[1],'tesla':hash_list[2]} print(user_auth) with open(auth_file,'w')as fw: fw.write(json.dumps(user_auth)) fw.close() def authentication(data): with open(auth_file,'r')as fr: user_info = json.loads(fr.read()) fr.close() if data[0] in user_info and data[1] == user_info[data[0]]: print('authentication is successful') return True else: return False
#author:nie cheng ping # _*_ coding=gbk _*_ import os import struct import json import socket from server.conf import info from server.conf.info import authentication import re class FTPserver: ftps_file = info.ftp_s_home package_size_tra = info.package_size str_code = info.coding listen = info.listen_line socket_net = info.socket_net socket_type = info.socket_type def __init__(self,server_ip_port,bind_active=True): self.server = server_ip_port self.socket = socket.socket(self.socket_net,self.socket_type) if bind_active: self.bind() self.listen_line() else: self.close_line() def bind(self): self.socket.bind(self.server) self.server_ip_port = self.socket.getsockname() def listen_line(self): self.socket.listen(self.listen) def wait_line(self): return self.socket.accept() def close_line(self): self.socket.close() def run_commands(self,cmd,user,path,active=True): if active: def function_struct(obj): header = {'package_size': len(obj)} header_json = json.dumps(header) header_json_bytes = header_json.encode(self.str_code) self.conn.send(struct.pack('i', len(header_json_bytes))) self.conn.send(header_json_bytes) self.conn.send(obj.encode(self.str_code)) try: path = path.split(' ',1) if cmd == 'ls': user_file_path = os.path.join(self.ftps_file,user) obj = os.listdir(user_file_path) if obj == []: obj = 'there is nothing' obj = json.dumps(obj) function_struct(obj) elif cmd == 'cd': os.chdir(path[1]) obj = os.getcwd() print(obj) function_struct(obj) else: obj = os.popen(cmd).read() if not obj: obj = 'commands is not defined' function_struct(obj) except ConnectionResetError: print('接收或执行异常') def get(self,cmd,user): share_file = os.path.join(self.ftps_file, cmd[1]) header = {'filename':cmd[1], 'file_size':os.path.getsize(share_file), 'md5':info.hash_data.hexdigest()} header_json = json.dumps(header) header_json_bytes = header_json.encode(self.str_code) header_struct = struct.pack('i',len(header_json_bytes)) print(header_struct) self.conn.send(header_struct) self.conn.send(header_json_bytes) data_len = header['file_size'] send_size = 0 with open(share_file,'rb')as f: for i in f: self.conn.send(i) send_size += len(i) def put(self,cmd,user,head_dic): #user为登录的用户名 cmd为操作命令list,[0]为操作,[1]为操作信息 share_file = os.path.join(self.ftps_file,user,cmd[1]) # header_struct = self.conn.recv(4) # header_len = struct.unpack('i',header_struct)[0] # header_json = self.conn.recv(header_len).decode(self.str_code) # header_dic = json.loads(header_json) recv_size = 0 total_size = head_dic['file_size'] with open(share_file, 'wb')as f: while recv_size < total_size: recv_data = self.conn.recv(self.package_size_tra) f.write(recv_data) recv_size += len(recv_data) else: print('receive file complete') return def summary(self): while True: print('wait line') self.conn,self.addr_ip = self.wait_line() # 这个位置后面的代码里添加线程池 print(self.addr_ip) while True: self.conn.send('输入用户名:'.encode(self.str_code)) user = self.conn.recv(self.package_size_tra) if not user:continue user = user.decode(self.str_code) self.conn.send('输入密码:'.encode(self.str_code)) password = self.conn.recv(self.package_size_tra) if not password:continue password = password.decode(self.str_code) # 生成用户账号、密码 user_pass = (user,password) flag = authentication(user_pass) # 认证信息是否成功 if flag == False: self.conn.send('authentication is false'.encode(self.str_code)) continue else: self.conn.send('ok'.encode(self.str_code)) user_file_path = os.path.join(self.ftps_file,user) if not os.path.exists(user_file_path): os.mkdir(user_file_path) while True: data = self.conn.recv(self.package_size_tra) if not data:continue datas = data.decode(self.str_code) cmd = datas.split() if cmd[0] == 'get': if not os.path.exists(os.path.join(self.ftps_file,cmd[1])): continue self.get(cmd,user) elif cmd[0] == 'put': header_struct = self.conn.recv(4) header_len = struct.unpack('i', header_struct)[0] header_json = self.conn.recv(header_len).decode(self.str_code) header_dic = json.loads(header_json) file_data_size = 0 if header_dic['file_size'] > info.total_package[user]: self.conn.send('file is too bigger'.encode(self.str_code)) continue if os.listdir(user_file_path) == []: self.conn.send('ok'.encode(self.str_code)) self.put(cmd, user, header_dic) continue for i in os.listdir(user_file_path): file_data_size += os.path.getsize(os.path.join(user_file_path,i)) if file_data_size < info.total_package[user]: if info.total_package[user] - file_data_size > header_dic['file_size']: self.conn.send('ok'.encode(self.str_code)) self.put(cmd,user,header_dic) else: self.conn.send('file is too bigger'.encode(self.str_code)) continue else: self.run_commands(cmd[0],user,datas) continue
# author:nie cheng ping from client.core.main import FTPclient from client.conf_c import info_c import sys base_dir = info_c.base_dir sys.path.insert(0,base_dir) if __name__ == '__main__': ftp_client = FTPclient(('127.0.0.1',8081)) ftp_client.summary() # 汇总程序功能!测试通过后设置端口ip复用
#author:nie cheng ping # _*_ coding=gbk _*_ import os import socket import string import hashlib import random base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) user_file_dir = 'file_position' coding = 'gbk' md5_data = ''.join(random.sample(string.digits,6)) hash_data = hashlib.md5() hash_data.update(md5_data.encode(coding)) file_path_c = os.path.join(base_dir,user_file_dir) package_size = 2048 socket_net = socket.AF_INET socket_type = socket.SOCK_STREAM commands_list = ['run_commands','get','put']
#author:nie cheng ping # _*_ coding=gbk _*_ import os import socket import string import hashlib import random base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) user_file_dir = 'file_position' coding = 'gbk' md5_data = ''.join(random.sample(string.digits,6)) hash_data = hashlib.md5() hash_data.update(md5_data.encode(coding)) file_path_c = os.path.join(base_dir,user_file_dir) package_size = 2048 socket_net = socket.AF_INET socket_type = socket.SOCK_STREAM commands_list = ['run_commands','get','put']
哎,没什么文采,就这么将就一下了,上班忙,慢慢改进吧。