作业:开发一个支持多用户在线的FTP程序

要求:

  1. 用户加密认证
  2. 允许同时多用户登录
  3. 每个用户有自己的家目录 ,且只能访问自己的家目录
  4. 对用户进行磁盘配额,每个用户的可用空间不同
  5. 允许用户在ftp server上随意切换目录
  6. 允许用户查看当前目录下文件
  7. 允许上传和下载文件,保证文件一致性
  8. 文件传输过程中显示进度条
  9. 附加功能:支持文件的断点续传(仅下载)

程序

1、最最重要的readme:

  1. ### 作者介绍:
  2. * authorlzl
  3. ### 博客地址:
  4. * http://www.cnblogs.com/lianzhilei/p/5813986.html
  5.  
  6. ### 功能实现
  7. 作业:开发一个支持多用户在线的FTP程序
  8. 要求:
  9. 用户加密认证
  10. 允许同时多用户登录
  11. 每个用户有自己的家目录 ,且只能访问自己的家目录
  12. 对用户进行磁盘配额,每个用户的可用空间不同
  13. 允许用户在ftp server上随意切换目录
  14. 允许用户查看当前目录下文件
  15. 允许上传和下载文件,保证文件一致性
  16. 文件传输过程中显示进度条
  17. 附加功能:支持文件的断点续传
  18.  
  19. ### 目录结构:
  20. FTP

  21. ├── ftpclient #客户端程序
  22. ├── __init__.py
  23. └── ftpclient.py #客户端主程序
  24. └── ftpserver #服务端程序
  25. ├── README.txt
  26. ├── ftpserver.py #服务端入口程序
  27. ├── conf #配置文件目录
  28. ├── __init__.py
  29. └── setting.py
  30. ├── modules #程序核心目录
  31. ├── __init__.py
  32. ├── auth_user.py #用户认证模块
  33. └── sokect_server.py #sokectserver模块
  34. ├── database #用户数据库
  35. ├── alex.db
  36. ├── lzl.db
  37. └── eric.db
  38. ├── home #用户宿主目录
  39. ├── alex
  40. ├── lzl
  41. └── eric
  42. └── log
  43. ├── __init__.py
  44. └── log #待扩展....
  45.  
  46. ### 功能实现
  47.  
  48. 1conf目录下settings.py模块记录可操作用户信息,根据用户信息生成用户字典和宿主目录,已经生成的不再新建
  49. 2、每个用户的宿主目录磁盘空间配额默认为10M,可在settings.py模块里进行修改
  50. 3、程序运行在windows系统上,程序要求全部实现,下面是具体命令操作
  51. 4、切换目录:cd .. 返回上一级目录 cd dirname 进入dirname
  52. 用户登录后默认进入宿主目录,只可在宿主目录下随意切换
  53.  
  54. 5、创建目录:mkdir dirname
  55. 在当前目录下创建目录,如果目录存在则报错,不存在创建
  56.  
  57. 6、查看当前路径: pwd
  58.  
  59. 7、查看当前路径下的文件名和目录名: dir
  60.  
  61. 8、下载文件(可续传):get filename
  62. ①、服务端当前目录存在此文件,客户端不存在此文件,直接下载
  63. ②、服务端当前目录存在此文件,客户端存在此文件名,之前下载中断,文件可续传,进行续传
  64. ③、服务端当前目录存在此文件,客户端存在此文件名,大小与服务端一致,不下载
  65.  
  66. 9、上传文件:put filename
  67. 判断宿主目录磁盘空间是否够用,可以,上传文件;否则,报错
  68.  
  69. ### 状态码
  70.  
  71. 400 用户认证失败
  72. 401 命令不正确
  73. 402 文件不存在
  74. 403 创建文件已经存在
  75. 404 磁盘空间不够
  76. 405 不续传
  77.  
  78. 200 用户认证成功
  79. 201 命令可以执行
  80. 202 磁盘空间够用
  81. 203 文件具有一致性
  82. 205 续传
  83.  
  84. 000 系统交互码

Readme

2、程序目录结构:

3、ftp客户端

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. #-Author-Lian
  4.  
  5. import socket
  6. import os,sys
  7. import hashlib
  8.  
  9. class Myclient():
  10. '''ftp客户端'''
  11. def __init__(self,ip_port):
  12. self.ip_port = ip_port
  13.  
  14. def connect(self):
  15. '''连接服务器'''
  16. self.client = socket.socket()
  17. self.client.connect(self.ip_port)
  18.  
  19. def start(self):
  20. '''程序开始'''
  21. self.connect()
  22. while True:
  23. username = input("输入用户名:").strip()
  24. password = input("输入密码:").strip()
  25. login_info = ("%s:%s" %(username, password))
  26. self.client.sendall(login_info.encode()) #发送用户密码信息
  27. status_code = self.client.recv(1024).decode() #返回状态码
  28. if status_code == "":
  29. print("[%s]用户密码认证错误"%status_code)
  30. continue
  31. else:print("[%s]用户密码认证成功"%status_code)
  32. self.interactive()
  33.  
  34. def interactive(self):
  35. '''开始交互'''
  36. while True:
  37. command = input("->>").strip()
  38. if not command:continue
  39. #if command == "exit":break
  40. command_str = command.split()[0]
  41. if hasattr(self,command_str): # 执行命令
  42. func = getattr(self,command_str)
  43. func(command)
  44. else:print("[%s]命令不存在"%401)
  45.  
  46. def get(self,command):
  47. '''下载文件'''
  48. self.client.sendall(command.encode()) #发送要执行的命令
  49. status_code = self.client.recv(1024).decode()
  50. if status_code == "": #命令可执行
  51. filename = command.split()[1]
  52.  
  53. # 文件名存在,判断是否续传
  54. if os.path.isfile(filename):
  55. revice_size = os.stat(filename).st_size #文件已接收大小
  56. self.client.sendall("".encode())
  57. response = self.client.recv(1024)
  58. self.client.sendall(str(revice_size).encode()) #发送已接收文件大小
  59. status_code = self.client.recv(1024).decode()
  60.  
  61. # 文件大小不一致,续传
  62. if status_code == "":
  63. print("继续上次上传位置进行续传")
  64. self.client.sendall("".encode())
  65.  
  66. # 文件大小一致,不续传,不下载
  67. elif status_code == "":
  68. print("文件已经存在,大小一致")
  69. return
  70.  
  71. # 文件不存在
  72. else:
  73. self.client.sendall("".encode())
  74. revice_size = 0
  75.  
  76. file_size = self.client.recv(1024).decode() #文件大小
  77. file_size = int(file_size)
  78. self.client.sendall("".encode())
  79.  
  80. with open(filename,"ab") as file: #开始接收
  81. #file_size 为文件总大小
  82. file_size +=revice_size
  83. m = hashlib.md5()
  84. while revice_size < file_size:
  85. minus_size = file_size - revice_size
  86. if minus_size > 1024:
  87. size = 1024
  88. else:
  89. size = minus_size
  90. data = self.client.recv(size)
  91. revice_size += len(data)
  92. file.write(data)
  93. m.update(data)
  94. self.__progress(revice_size,file_size,"下载中") #进度条
  95. new_file_md5 = m.hexdigest() #生成新文件的md5值
  96. server_file_md5 = self.client.recv(1024).decode()
  97. if new_file_md5 == server_file_md5: #md5值一致
  98. print("\n文件具有一致性")
  99. else:print("[%s] Error!"%(status_code))
  100.  
  101. def put(self,command):
  102. '''上传文件'''
  103. if len(command.split()) > 1:
  104. filename = command.split()[1]
  105. #file_path = self.current_path + r"\%s"%filename
  106. if os.path.isfile(filename): #文件是否存在
  107. self.client.sendall(command.encode()) #发送要执行的命令
  108. response = self.client.recv(1024) #收到ack确认
  109.  
  110. file_size = os.stat(filename).st_size # 文件大小
  111. self.client.sendall(str(file_size).encode()) # 发送文件大小
  112. status_code = self.client.recv(1024).decode() # 等待响应,返回状态码
  113. if status_code == "":
  114. with open(filename,"rb") as file:
  115. m = hashlib.md5()
  116. for line in file:
  117. m.update(line)
  118. send_size = file.tell()
  119. self.client.sendall(line)
  120. self.__progress(send_size, file_size, "上传中") # 进度条
  121. self.client.sendall(m.hexdigest().encode()) #发送文件md5值
  122. status_code = self.client.recv(1024).decode() #返回状态码
  123. if status_code == "":
  124. print("\n文件具有一致性")
  125. else:print("[%s] Error!"%(status_code))
  126. else:
  127. print("[402] Error")
  128. else: print("[401] Error")
  129.  
  130. def dir(self,command):
  131. '''查看当前目录下的文件'''
  132. self.__universal_method_data(command)
  133. pass
  134.  
  135. def pwd(self,command):
  136. '''查看当前用户路径'''
  137. self.__universal_method_data(command)
  138. pass
  139.  
  140. def mkdir(self,command):
  141. '''创建目录'''
  142. self.__universal_method_none(command)
  143. pass
  144.  
  145. def cd(self,command):
  146. '''切换目录'''
  147. self.__universal_method_none(command)
  148. pass
  149.  
  150. def __progress(self, trans_size, file_size,mode):
  151. '''
  152. 显示进度条
  153. trans_size: 已经传输的数据大小
  154. file_size: 文件的总大小
  155. mode: 模式
  156. '''
  157. bar_length = 100 #进度条长度
  158. percent = float(trans_size) / float(file_size)
  159. hashes = '=' * int(percent * bar_length) #进度条显示的数量长度百分比
  160. spaces = ' ' * (bar_length - len(hashes)) #定义空格的数量=总长度-显示长度
  161. sys.stdout.write(
  162. "\r%s:%.2fM/%.2fM %d%% [%s]"%(mode,trans_size/1048576,file_size/1048576,percent*100,hashes+spaces))
  163. sys.stdout.flush()
  164.  
  165. def __universal_method_none(self,command):
  166. '''通用方法,无data输出'''
  167. self.client.sendall(command.encode()) # 发送要执行的命令
  168. status_code = self.client.recv(1024).decode()
  169. if status_code == "": # 命令可执行
  170. self.client.sendall("".encode()) # 系统交互
  171. else:
  172. print("[%s] Error!" % (status_code))
  173.  
  174. def __universal_method_data(self,command):
  175. '''通用方法,有data输出'''
  176. self.client.sendall(command.encode()) #发送要执行的命令
  177. status_code = self.client.recv(1024).decode()
  178. if status_code == "": #命令可执行
  179. self.client.sendall("".encode()) #系统交互
  180. data = self.client.recv(1024).decode()
  181. print(data)
  182. else:print("[%s] Error!" % (status_code))
  183.  
  184. if __name__ == "__main__":
  185. ip_port =("127.0.0.1",9999) #服务端ip、端口
  186. client = Myclient(ip_port) #创建客户端实例
  187. client.start() #开始连接

ftpclient.py

4、ftp服务端

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. #-Author-Lian
  4.  
  5. import os,hashlib
  6. import json
  7. from conf import settings
  8. from modules import auth_user
  9. from modules import sokect_server
  10.  
  11. def create_db():
  12. '''创建用户数据库文件'''
  13. user_database={}
  14. encryption = auth_user.User_operation()
  15. limitsize = settings.LIMIT_SIZE
  16. for k,v in settings.USERS_PWD.items():
  17. username = k
  18. password = encryption.hash(v)
  19. user_db_path = settings.DATABASE + r"\%s.db"%username
  20. user_home_path = settings.HOME_PATH + r"\%s"%username
  21. user_database["username"] = username
  22. user_database["password"] = password
  23. user_database["limitsize"] = limitsize
  24. user_database["homepath"] = user_home_path
  25. if not os.path.isfile(user_db_path):
  26. with open(user_db_path,"w") as file:
  27. file.write(json.dumps(user_database))
  28.  
  29. def create_dir():
  30. '''创建用户属主目录'''
  31. for username in settings.USERS_PWD:
  32. user_home_path = settings.HOME_PATH + r"\%s" %username
  33. if not os.path.isdir(user_home_path):
  34. os.popen("mkdir %s" %user_home_path)
  35.  
  36. if __name__ == "__main__":
  37. '''初始化系统数据并启动程序'''
  38. create_db() #创建数据库
  39. create_dir() #创建属主目录
  40. #启动ftp服务
  41. server = sokect_server.socketserver.ThreadingTCPServer(settings.IP_PORT, sokect_server.Myserver)
  42. server.serve_forever()

ftpserver.py

5、conf配置文件

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. #-Author-Lian
  4.  
  5. import os,sys
  6.  
  7. #程序主目录文件
  8. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  9. #添加环境变量
  10. sys.path.insert(0,BASE_DIR)
  11.  
  12. #数据库目录
  13. DATABASE = os.path.join(BASE_DIR,"database")
  14.  
  15. #用户属主目录
  16. HOME_PATH = os.path.join(BASE_DIR,"home")
  17.  
  18. #用户字典
  19. USERS_PWD = {"alex":"","lzl":"","eric":""}
  20.  
  21. #磁盘配额 10M
  22. LIMIT_SIZE = 10240000
  23.  
  24. #ftp服务端口
  25. IP_PORT = ("0.0.0.0",9999)

settings.py

6、database用户数据库(系统初始化自动生成)

  1. {"username": "alex", "password": "e10adc3949ba59abbe56e057f20f883e", "limitsize": 10240000, "homepath": "C:\\Users\\L\\PycharmProjects\\s14\\homework\\Day8\\FTP\\ftpserver\\home\\alex"}

lzl.db

  1. {"username": "eric", "password": "e9510081ac30ffa83f10b68cde1cac07", "limitsize": 10240000, "homepath": "C:\\Users\\L\\PycharmProjects\\s14\\homework\\Day8\\FTP\\ftpserver\\home\\eric"}

eric.db

  1. {"username": "alex", "password": "e10adc3949ba59abbe56e057f20f883e", "limitsize": 10240000, "homepath": "C:\\Users\\L\\PycharmProjects\\s14\\homework\\Day8\\FTP\\ftpserver\\home\\alex"}

alex.db

7、modules模块dd

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. #-Author-Lian
  4.  
  5. import json
  6. import sys,os
  7. import hashlib
  8. from conf import settings
  9.  
  10. class User_operation():
  11. '''对登录信息进行认证,登录成功返回用户名,失败返回None'''
  12. def authentication(self,login_info):
  13. list = login_info.split(":") #对信息进行分割
  14. login_name = list[0]
  15. login_passwd = self.hash(list[1])
  16. DB_FILE = settings.DATABASE + r"\%s.db"%login_name
  17. if os.path.isfile(DB_FILE):
  18. user_database = self.cat_database(DB_FILE) #用户数据库信息
  19. if login_name == user_database["username"]:
  20. if login_passwd == user_database["password"]:
  21. return user_database
  22.  
  23. def cat_database(self,DB_FILE):
  24. #获取数据库信息
  25. with open(DB_FILE,"r") as file:
  26. data = json.loads(file.read())
  27. return data
  28.  
  29. def hash(self,passwd):
  30. '''对密码进行md5加密'''
  31. m = hashlib.md5()
  32. m.update(passwd.encode("utf-8"))
  33. return m.hexdigest()

auth_user.py

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. #-Author-Lian
  4.  
  5. import socketserver
  6. import sys,os
  7. import hashlib
  8. from os.path import join, getsize
  9. from conf import settings
  10. from modules import auth_user
  11.  
  12. class Myserver(socketserver.BaseRequestHandler):
  13. '''ftp服务端'''
  14. def handle(self):
  15. try:
  16. self.conn = self.request
  17. while True:
  18. login_info = self.conn.recv(1024).decode() # 接收客户端发的的账号密码信息
  19. result = self.authenticat(login_info)
  20. status_code = result[0]
  21. self.conn.sendall(status_code.encode())
  22. if status_code == "":
  23. continue
  24. self.user_db = result[1] #当前登录用户信息
  25. self.current_path = self.user_db["homepath"] #用户当前目录
  26. self.home_path = self.user_db["homepath"] #用户宿主目录
  27.  
  28. while True:
  29. command = self.conn.recv(1024).decode()
  30. command_str = command.split()[0]
  31. if hasattr(self,command_str):
  32. func = getattr(self,command_str)
  33. func(command)
  34. else:self.conn.sendall("".encode())
  35. except ConnectionResetError as e:
  36. self.conn.close()
  37. print(e)
  38.  
  39. def authenticat(self,login_info):
  40. '''认证用户'''
  41. auth = auth_user.User_operation() # 创建认证实例
  42. result = auth.authentication(login_info) # 认证用户
  43. if result:return "",result
  44. else:return "",result
  45.  
  46. def get(self,command):
  47. '''下载文件'''
  48. if len(command.split()) > 1:
  49. filename = command.split()[1]
  50. file_path = self.current_path + r"\%s"%filename
  51. if os.path.isfile(file_path): #文件是否存在
  52. self.conn.sendall("".encode()) #命令可执行
  53. file_size = os.stat(file_path).st_size # 文件总大小
  54. status_code = self.conn.recv(1024).decode()
  55.  
  56. # 客户端存在此文件
  57. if status_code == "":
  58. self.conn.sendall("".encode()) #系统交互
  59. has_send_size = self.conn.recv(1024).decode()
  60. has_send_size = int(has_send_size)
  61. # 客户端文件不完整可续传
  62. if has_send_size < file_size:
  63. self.conn.sendall("".encode())
  64. file_size -= has_send_size #续传文件大小
  65. response = self.conn.recv(1024) # 等待响应
  66.  
  67. # 客户端文件完整不可续传、不提供下载
  68. else:
  69. self.conn.sendall("".encode())
  70. return
  71. # 客户端不存在此文件
  72. elif status_code == "":
  73. has_send_size = 0
  74.  
  75. with open(file_path,"rb") as file:
  76. self.conn.sendall(str(file_size).encode()) #发送文件大小
  77. response = self.conn.recv(1024) #等待响应
  78. file.seek(has_send_size)
  79. m = hashlib.md5()
  80. for line in file:
  81. m.update(line)
  82. self.conn.sendall(line)
  83. self.conn.sendall(m.hexdigest().encode()) #发送文件md5值
  84. else:self.conn.sendall("".encode())
  85. else:self.conn.sendall("".encode())
  86.  
  87. def put(self,command):
  88. '''上传文件'''
  89. filename = command.split()[1]
  90. file_path = self.current_path + r"\%s" % filename
  91. self.conn.sendall("".encode()) #发送确认
  92. file_size = self.conn.recv(1024).decode() # 文件大小
  93. file_size = int(file_size)
  94. limit_size = self.user_db["limitsize"] #磁盘额度
  95. used_size = self.__getdirsize(self.home_path) #已用空间大小
  96. if limit_size >= file_size+used_size:
  97. self.conn.sendall("".encode())
  98. with open(file_path, "wb") as file: # 开始接收
  99. revice_size = 0
  100. m = hashlib.md5()
  101. while revice_size < file_size:
  102. minus_size = file_size - revice_size
  103. if minus_size > 1024:
  104. size = 1024
  105. else:
  106. size = minus_size
  107. data = self.conn.recv(size)
  108. revice_size += len(data)
  109. file.write(data)
  110. m.update(data)
  111. new_file_md5 = m.hexdigest() # 生成新文件的md5值
  112. server_file_md5 = self.conn.recv(1024).decode()
  113. if new_file_md5 == server_file_md5: # md5值一致
  114. self.conn.sendall("".encode())
  115. else:self.conn.sendall("".encode())
  116.  
  117. def dir(self,command):
  118. '''查看当前目录下的文件'''
  119. if len(command.split()) == 1:
  120. self.conn.sendall("".encode())
  121. response = self.conn.recv(1024)
  122. send_data = os.popen("dir %s"%self.current_path)
  123. self.conn.sendall(send_data.read().encode())
  124. else:self.conn.sendall("".encode())
  125.  
  126. def pwd(self,command):
  127. '''查看当前用户路径'''
  128. if len(command.split()) == 1:
  129. self.conn.sendall("".encode())
  130. response = self.conn.recv(1024)
  131. send_data = self.current_path
  132. self.conn.sendall(send_data.encode())
  133. else:self.conn.sendall("".encode())
  134.  
  135. def mkdir(self,command):
  136. '''创建目录'''
  137. if len(command.split()) > 1:
  138. dir_name = command.split()[1] #目录名
  139. dir_path = self.current_path + r"\%s"%dir_name #目录路径
  140. if not os.path.isdir(dir_path): #目录不存在
  141. self.conn.sendall("".encode())
  142. response = self.conn.recv(1024)
  143. os.popen("mkdir %s"%dir_path)
  144. else:self.conn.sendall("".encode())
  145. else:self.conn.sendall("".encode())
  146.  
  147. def cd(self,command):
  148. '''切换目录'''
  149. if len(command.split()) > 1:
  150. dir_name = command.split()[1] #目录名
  151. dir_path = self.current_path + r"\%s" %dir_name #目录路径
  152. user_home_path = settings.HOME_PATH + r"\%s"%self.user_db["username"] #宿主目录
  153. if dir_name == ".." and len(self.current_path)>len(user_home_path):
  154. self.conn.sendall("".encode())
  155. response = self.conn.recv(1024)
  156. self.current_path = os.path.dirname(self.current_path) #返回上一级目录
  157. elif os.path.isdir(dir_path) :
  158. self.conn.sendall("".encode())
  159. response = self.conn.recv(1024)
  160. if dir_name != "." and dir_name != "..":
  161. self.current_path += r"\%s"%dir_name #切换目录
  162.  
  163. else:self.conn.sendall("".encode())
  164. else:self.conn.sendall("".encode())
  165.  
  166. def __getdirsize(self,home_path):
  167. '''统计目录空间大小'''
  168. size = 0
  169. for root, dirs, files in os.walk(home_path):
  170. size += sum([getsize(join(root, name)) for name in files])
  171. return size

sokect_server.py

效果图:

下载:

续传:

Python开发程序:FTP程序的更多相关文章

  1. 用python开发简单ftp程序

    根据alex老师视频开发的简单ftp程序,只能实现简单的get功能 ftp客户端程序: #!/usr/bin/env python #_*_ coding:utf-8 _*_ import socke ...

  2. elipse+pydev+python开发arcgis脚本程序

    环境配置参考:http://www.cnblogs.com/halfacre/archive/2012/07/22/2603848.html 添加arcpy类库.arctoolbox.arcgis-b ...

  3. 使用Python开发鸿蒙设备程序(0-初体验)

    到目前为止,鸿蒙设备开发的"官方指定语言"还是C语言! 这看起来是一件正常的事,毕竟鸿蒙设备开发还是属于嵌入式开发的范畴,而在嵌入式开发中C语言又是当之无愧的首选,所以,大家也都接 ...

  4. C++ Builder平台使用Indy9开发自动FTP程序01

    Indy9与CB自带的Indy8不同处还是挺多的.首先就是图标变漂亮了,其次很多Method都重写了.它主要是依据Delph里的函数,力求与之相通.不同点在本系列的后续章节中会一一介绍. 在写ftp代 ...

  5. python简单的ftp程序

    服务器端 '''1.读取文件名2.检测文件是否存在3.打开文件4.检测文件大小5.发送文件大小给客户端6.等客户端确认7.开始边读边发数据8.发送md5'''import socket,os,time ...

  6. 2020年python开发微信小程序,公众号,手机购物商城APP

    2020年最新的技术全栈,手机短信注册登陆等运用, 精准定位用户 支付宝支付 以及前后端从0到大神的全部精解 2020年最新的技术全栈,手机短信注册登陆等运用, 精准定位用户 支付宝支付 以及前后端从 ...

  7. python如何编写win程序

    python可以编写win程序.win程序的格式是exe,下面我们就来看一下使用python编写exe程序的方法. 编写好python程序后py2exe模块即可将其打包为exe程序. 实际操作过程: ...

  8. 用python开发android应用 【转载】

    用python开发android应用 [转载] 转载自:http://www.miui.com/thread-995114-1-1.html Python是动态语言,比较简洁.Android不直接支持 ...

  9. 用Python开发实用程序 – 计算器

    一段时间前,自己制作了一个库 “sui-math”.这其实是math的翻版.做完后,python既然可以轻易的完成任何的数学计算,何不用python开发一个小程序专门用以计算呢? 现在我们越来越依赖于 ...

随机推荐

  1. 如何查看项目svn路径

    1.选择项目根目录---->鼠标右键---->属性---->版本控制(Subversion) 如图:

  2. [转]基于gulp和webpack的前端工程化

    本文样例代码 :https://github.com/demohi/learning-gulp 本文主要简单介绍一下基于gulp和webpack的前端工程化. 技术栈 React.js reFlux ...

  3. Here's what C++ is

    Yes this article describes what c++ exactlyis http://www.skywind.me/blog/archives/1398#comment-3671 ...

  4. Android js相互调用

    一.webview相当于android中的浏览器,基于webkit开发,可以浏览网页文件,支持css javas cript 以及html webview.getSettings().setJavaS ...

  5. ACM 背包问题

    背包问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v,w< ...

  6. ACM: 限时训练题解- Travelling Salesman-最小生成树

    Travelling Salesman   After leaving Yemen, Bahosain now works as a salesman in Jordan. He spends mos ...

  7. require.js 入门学习 (share)

    以下内容转自阮一峰老师的网络日志:http://www.ruanyifeng.com/blog/2012/11/require_js.html 更多学习资源: require.js官网:http:// ...

  8. [深入浅出Windows 10]应用实战:Bing在线壁纸

    本章介绍一个使用Bing搜索引擎背景图接口实现的一个应用——Bing在线壁纸,讲解如何使用网络的接口来实现一个壁纸下载,壁纸列表展示和网络请求封装的内容.通过该例子我们可以学习到如何使用网络编程的知识 ...

  9. eclipse安装color theme插件

    为Eclipse添加Color.Theme的插件 这样可以方便一键更换主题,再也不用一个一个设置BackgroundColor了,同时也方便回退到default默认主题配置. 方法一: 打开Eclip ...

  10. Maven dependency spring-web vs spring-webmvc

    <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmv ...