Advertisement
Guest User

Untitled

a guest
Mar 1st, 2019
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.66 KB | None | 0 0
  1. import os
  2. import json
  3. import hashlib
  4. import struct
  5. import socket
  6.  
  7.  
  8. class Client:
  9. def __init__(self, ip_port):
  10. self.ip_port = ip_port
  11. self.client = socket.socket()
  12. self.client.connect(ip_port)
  13. self.current_path = None
  14. self.default_path = None
  15. self.main()
  16.  
  17. def main(self):
  18. """
  19. 初次进入选择功能
  20. :return:
  21. """
  22. choice = input("""\n欢迎进入垃圾云盘!!\n\t1 登陆\n\t2 注册\n\t3 退出\n\t请选择:""").strip()
  23. if choice == "1":
  24. self.login()
  25. if choice == "2":
  26. self.register()
  27. if choice == "3":
  28. self.client.close()
  29. else:
  30. self.main()
  31.  
  32. def handle(self):
  33. """
  34. 登陆成功选择操作
  35. :return:
  36. """
  37. dic = {"返回上一层": "last_dir",
  38. "进入下一层": "next_dir",
  39. "查看所有文件": "show_dir",
  40. "创建文件夹": "mk_dir",
  41. "删除文件夹": "rm_dir",
  42. "创建文件": "mk_file",
  43. "删除文件": "rm_file",
  44. "上传文件": "uploading",
  45. "下载文件": "download",
  46. "退出到登陆": "exit"
  47. }
  48. print("="*30)
  49. lst = list(dic.keys())
  50. for k, v in enumerate(lst, 0):
  51. print(k, v)
  52. num = input("请选择操作:")
  53. if num.isdigit() and (-1 < int(num) < len(lst)):
  54. key = lst[int(num)]
  55. self.send(dic[key])
  56. if hasattr(self, dic[key]):
  57. getattr(self, dic[key])()
  58. else:
  59. print("请重新选择!!")
  60. return self.handle()
  61.  
  62. def send(self, msg):
  63. """
  64. 防粘包,发送消息方法
  65. :param msg:
  66. :return:
  67. """
  68. msg = msg.encode()
  69. num = struct.pack("i", len(msg))
  70. self.client.send(num)
  71. self.client.send(msg)
  72.  
  73. def recv(self):
  74. """
  75. 防粘包,收取消息方法
  76. :return: 收取到的消息
  77. """
  78. num_bytes = self.client.recv(4)
  79. num = struct.unpack("i", num_bytes)[0]
  80. msg = self.client.recv(num).decode()
  81. return msg
  82.  
  83. def login(self):
  84. """
  85. 用户登录
  86. :return:
  87. """
  88. self.send("login")
  89. print("欢迎来到登录界面!!")
  90. username = input("请输入帐号:").strip()
  91. password = input("请输入密码:").strip()
  92. if len(username) < 20 and len(password) < 20:
  93. pwd_md5 = hashlib.md5(password.encode()).hexdigest()
  94. user_pwd = username+"|"+pwd_md5
  95. self.send(user_pwd)
  96. ret = self.recv()
  97. if ret == "1":
  98. print("登陆成功!!")
  99. current_path = self.recv()
  100. self.current_path = current_path
  101. self.default_path = current_path
  102. self.handle()
  103.  
  104. if ret == "0":
  105. print("登陆失败!!")
  106. self.main()
  107.  
  108. def register(self):
  109. """
  110. 用户账号注册
  111. :return:
  112. """
  113. self.send("register")
  114. print("欢迎来到注册界面!!")
  115. username = input("请输入帐号:").strip()
  116. password = input("请输入密码:").strip()
  117. if len(username) < 20 and len(password) < 20:
  118. pwd_md5 = hashlib.md5(password.encode()).hexdigest()
  119. user_pwd = username + "|" + pwd_md5
  120. self.send(user_pwd)
  121. ret = self.recv()
  122. if ret == "1":
  123. print("注册成功!!")
  124. self.login()
  125. if ret == "0":
  126. print("注册失败!!重新注册!!")
  127. self.register()
  128.  
  129. def exit(self):
  130. self.send("exit")
  131. self.main()
  132.  
  133. @staticmethod
  134. def md5(file_path):
  135. """
  136. 计算文件的md5值
  137. :param file_path: 需要计算的文件路径
  138. :return:
  139. """
  140. read_num = 0
  141. file_size = os.path.getsize(file_path)
  142. file_md5 = hashlib.md5()
  143. with open(file_path, "rb") as f:
  144. while read_num < file_size:
  145. read_size = f.read(1024)
  146. file_md5.update(read_size)
  147. read_num += len(read_size)
  148. return file_md5.hexdigest()
  149.  
  150. def last_dir(self):
  151. if self.current_path == self.default_path:
  152. print("当前文件夹已是顶级文件夹!!")
  153. self.send("error")
  154. else:
  155. last_dir = os.path.dirname(self.current_path)
  156. self.current_path = last_dir
  157. self.send(last_dir)
  158. self.handle()
  159.  
  160. def next_dir(self):
  161. """
  162. 进入下一层
  163. :return:
  164. """
  165. lst = self.show_dir(False)
  166. if lst:
  167. self.send("right")
  168. dir_name = input("请选择你要进入的文件夹:")
  169. if dir_name.isdigit() and (-1 < int(dir_name)-1 < len(lst)):
  170. self.send(lst[int(dir_name) - 1])
  171. ret = self.recv()
  172. if ret == "error":
  173. print("文件夹切换失败!!")
  174. self.next_dir()
  175. else:
  176. self.current_path = os.path.join(self.current_path, lst[int(dir_name) - 1])
  177. print("文件夹切换成功!!")
  178. self.handle()
  179. else:
  180. self.send("error")
  181. self.next_dir()
  182. else:
  183. self.send("error")
  184. print("该文件夹内无文件,请重新操作")
  185. self.handle()
  186.  
  187. def show_dir(self, status=True):
  188. """
  189. 显示当前目录下所有文件夹及文件
  190. :return:
  191. """
  192. print(f"当前文件目录为:{self.current_path}")
  193. str_lst = self.recv()
  194. lst = json.loads(str_lst)
  195. if lst:
  196. print("该目录下共有以下文件:")
  197. for k, v in enumerate(lst, 1):
  198. print(k, v)
  199. if status is True:
  200. self.handle()
  201. else:
  202. return lst
  203. else:
  204. print("该文件夹没有文件!!")
  205. return lst
  206.  
  207. def mk_dir(self):
  208. """
  209. 创建文件夹
  210. :return:
  211. """
  212. self.show_dir(False)
  213. dir_name = input("请输入你要创建的文件夹名称:")
  214. self.send(dir_name)
  215. msg = self.recv()
  216. if msg == "error":
  217. self.mk_dir()
  218. else:
  219. print("文件夹创建成功!!")
  220. self.handle()
  221.  
  222. def rm_dir(self):
  223. """
  224. 删除文件夹
  225. :return:
  226. """
  227. lst = self.show_dir(False)
  228. if lst:
  229. self.send("right")
  230. dir_name = input("请选择你要删除的文件夹:")
  231. if dir_name.isdigit() and (-1 < int(dir_name) < len(lst)-1):
  232. self.send(lst[int(dir_name)-1])
  233. print("文件夹删除成功!!")
  234. self.handle()
  235. else:
  236. print("文件夹删除失败!!")
  237. self.send("error")
  238. self.rm_dir()
  239. else:
  240. print("文件夹下无文件,请重新操作!!")
  241. self.send("error")
  242. self.handle()
  243.  
  244. def mk_file(self):
  245. """
  246. 创建文件
  247. :return:
  248. """
  249. self.show_dir(False)
  250. file_name = input("请输入你要创建的文件名称:")
  251. self.send(file_name)
  252. msg = self.recv()
  253. if msg == "error":
  254. print("文件创建失败!!")
  255. self.mk_file()
  256. else:
  257. print("文件夹创建成功!!")
  258. self.handle()
  259.  
  260. def rm_file(self):
  261. """
  262. 删除文件
  263. :return:
  264. """
  265. lst = self.show_dir(False)
  266. if lst:
  267. self.send("right")
  268. file_name = input("请选择你要删除的文件夹:")
  269. if file_name.isdigit() and (-1 < int(file_name) < len(lst) - 1):
  270. self.send(lst[int(file_name) - 1])
  271. print("文件删除成功!!")
  272. self.handle()
  273. else:
  274. print("文件删除失败!!")
  275. self.send("error")
  276. self.rm_dir()
  277. else:
  278. self.send("error")
  279. print("该文件夹下无文件!!")
  280. self.handle()
  281.  
  282. def download(self):
  283. """
  284. 用户下载功能
  285. :return:
  286. """
  287. lst = self.show_dir(False)
  288. if lst:
  289. self.send("right")
  290. dir_name = input("请选择你要下载的文件:")
  291. if dir_name.isdigit() and (-1 < int(dir_name) - 1 < len(lst)):
  292. self.send(lst[int(dir_name) - 1])
  293. ret = self.recv()
  294. if ret == "error":
  295. print("文件下载失败!!")
  296. self.download()
  297. else:
  298. num_bytes = self.client.recv(4)
  299. num = struct.unpack("i", num_bytes)[0]
  300. json_bytes = self.client.recv(num).decode()
  301. dic = json.loads(json_bytes)
  302. file_name = dic["file_name"]
  303. file_md5 = dic["file_md5"]
  304. file_size = dic["file_size"]
  305. file_path = os.path.join("D:\\Downloads", file_name)
  306. file_dir = os.path.dirname(file_path)
  307. if not os.path.exists(file_dir):
  308. os.makedirs(file_dir)
  309. with open(file_path, "wb") as f:
  310. recv_size = f.seek(0, 2)
  311. # 将光标移动到文件末尾,并返回已传输的文件字节数
  312. self.send(str(recv_size))
  313. # 上传功能的断点续传,将已收到的文件字节数发送给客户端
  314. while recv_size < file_size:
  315. recv_data = self.client.recv(1024)
  316. recv_size += len(recv_data)
  317. self.progress(recv_size/file_size)
  318. f.write(recv_data)
  319. new_md5 = self.md5(file_path)
  320. if new_md5 == file_md5:
  321. self.client.send("right".encode())
  322. print("文件下载成功!!")
  323. self.handle()
  324. else:
  325. self.client.send("error".encode())
  326. self.download()
  327. else:
  328. self.send("error")
  329. self.download()
  330. else:
  331. self.send("error")
  332. print("该文件夹下无文件!!")
  333. self.handle()
  334.  
  335. def uploading(self):
  336. """
  337. 用户上传功能
  338. :return:
  339. """
  340. disk = input("请输入您要选择的盘符:").strip()
  341. disk = disk.upper() + ":\\"
  342. try:
  343. file_path = self.choice_file(disk, disk)
  344. except FileNotFoundError:
  345. print("你输入的磁盘路径有误!!")
  346. self.uploading()
  347. else:
  348. file_name = os.path.basename(file_path)
  349. file_md5 = self.md5(file_path)
  350. file_size = os.path.getsize(file_path)
  351. dic = {
  352. "file_name": file_name,
  353. "file_md5": file_md5,
  354. "file_size": file_size,
  355. }
  356. json_bytes = json.dumps(dic)
  357. num = struct.pack("i", len(json_bytes))
  358. self.client.send(num)
  359. self.client.send(json_bytes.encode())
  360. send_size = 0
  361. with open(file_path, "rb") as f:
  362. num = self.recv()
  363. if num != 0:
  364. f.seek(int(num))
  365. # 断点续传
  366. while send_size < file_size:
  367. read_data = f.read(1024)
  368. send_data = self.client.send(read_data)
  369. send_size += send_data
  370. self.progress(send_size / file_size)
  371. # 进度条实现
  372. ret = self.recv()
  373. if ret == "right":
  374. print("文件上传完成!!")
  375. self.handle()
  376. else:
  377. self.uploading()
  378.  
  379. def choice_file(self, path, default_path="D:"):
  380. """
  381. 用户上传文件时选择文件
  382. :param path: 用户输入的盘符
  383. :param default_path: 默认盘符
  384. :return: 用户选择的文件,绝对路径
  385. """
  386. list_dir = os.listdir(path)
  387. for k, v in enumerate(list_dir, 1):
  388. v = os.path.join(path, v)
  389. if os.path.isdir(v):
  390. print(k, v, "文件夹")
  391. if os.path.isfile(v):
  392. print(k, v, "文件")
  393. num = input("请选择序号0返回上一层:")
  394. if num.isdigit():
  395. num = int(num)
  396. if num == 0:
  397. if path == default_path:
  398. print("已经是最顶层了!!")
  399. return self.choice_file(path)
  400. else:
  401. upper_path = os.path.dirname(path)
  402. return self.choice_file(upper_path)
  403. if 0 < num < len(list_dir) + 1:
  404. choice = list_dir[num - 1]
  405. new_path = os.path.join(path, choice)
  406. if os.path.isdir(new_path):
  407. return self.choice_file(new_path)
  408. else:
  409. return new_path
  410. else:
  411. print("请正确输入!!")
  412.  
  413. @staticmethod
  414. def progress(percent, width=100):
  415. """
  416. 显示进度条函数
  417. :param percent: 数据百分比
  418. :param width: 进度条宽度,默认100
  419. """
  420. if percent >= 1:
  421. percent = 1
  422. print(format(f"\r[{int(width*percent)*'#'}", f"<{width}"), f"] {int(percent*100)}%", end="")
  423.  
  424.  
  425. if __name__ == '__main__':
  426. Client(("127.0.0.1", 10010))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement