在windows下开发后台服务, 经常需要提供FTP服务, 以提供稳定的文件上传,下载服务.
windows作为一个成熟稳定的平台, 网上提供大量的收费,免费软件.
经过一番调研之后, 发现多数软件都是直接面向用户的(带界面),需要用户单独安装后才能使用. 对于开发者而言,并不优好.
部署便捷性
稳定性
笔者的服务器是基于Cplusplus开发的windows程序
既然C++ 没有现成的FTP服务器, java和C#总是有的啊. 基本的功能都能很好的符合需求. 但是需要携带一个 jre 或者.net framework的环境包. 一个FTP功能,就比主程序功能还大. 太说不过去了. 此路不适合
几经调查,笔者将目标锁定到python的pyftpdlib库上. 基本一下特点:
1. 接口简单,友好,容易上手
2. 功能丰富,可面向编程使用
3. 轻量级
4. 自带支持命令行启动FTP
考虑到python可以使用py2exe,将编译语言转换成exe文件执行. 体积上可以大大减小. 能够做到绿色版
话不多数, 放码出来
[base]
anonymous = 1 ;是否允许匿名登录
user = ITC ;用户名
password = ITC123 ;密码
port = 2121 ;侦听端口号
dir = c://new/test/good ;#默认路径
hided = 0 ;是否隐藏当前窗口
[advanced]
max_connect =256 ;同时最大允许连接数
permission = elradfmw ;允许权限
autosetup = 1 ;是否随机启动
;Read permissions:
;- "e" = change directory (CWD command)
;- "l" = list files (LIST, NLST, STAT, MLSD, MLST, SIZE, MDTM commands)
;- "r" = retrieve file from the server (RETR command)
;
;Write permissions:
;- "a" = append data to an existing file (APPE command)
;- "d" = delete file or directory (DELE, RMD commands)
;- "f" = rename file or directory (RNFR, RNTO commands)
;- "m" = create directory (MKD command)
;- "w" = store a file to the server (STOR, STOU commands)
;- "M" = change file mode (SITE CHMOD command)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ConfigParser
import os, sys
import ctypes
sys.path.append(os.path.abspath('..'))
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import ThreadedFTPServer
from Logger import logger
import platform
g_user =u"ITC"
g_password =u"ITC123"
g_dir =u"c:"
g_port =2121
g_banonymous = False
g_hided = False
# advanced feature
g_max_connect=256
g_permission = "elradfmw" #允许权限
g_bautostartup = 0 #是否随机启动
def read_config():
global g_user
global g_password
global g_dir
global g_port
global g_banonymous
global g_hided
global g_bautostartup
global g_max_connect
global g_permission
try:
cf = ConfigParser.ConfigParser()
cf.read(os.path.join(os.getcwd(), "FtpConfig.ini"))
if cf.has_option("base","user"):
g_user = cf.get("base", "user").decode("GBK")
if cf.has_option("base","password"):
g_password = cf.get("base", "password").decode("GBK")
if cf.has_option("base","dir"):
g_dir = cf.get("base", "dir", sys.path[0]).decode("GBK")
if cf.has_option("base","port"):
g_port = cf.getint("base", "port")
if cf.has_option("base","anonymous"):
g_banonymous = cf.getboolean("base", "anonymous")
if cf.has_option("base","hided"):
g_hided = cf.getboolean("base" , "hided")
#high level feature
if cf.has_option("advanced","max_connect"):
g_max_connect = cf.getint("advanced","max_connect" )
if cf.has_option("advanced","permission"):
g_permission = cf.get("advanced","permission","elradfmw").decode("GBK")
if cf.has_option("advanced","autosetup"):
g_bautostartup = cf.getboolean("advanced", "autosetup")
check_ini_para()
auto_setup(g_bautostartup)
return True
except Exception, ex:
print ex
logger.error(ex)
os.system("pause")
return False
def check_ini_para():
global g_user
global g_password
global g_dir
global g_port
global g_banonymous
global g_hided
global g_bautostartup
global g_max_connect
global g_permission
if len(g_permission) == 0:
g_permission = "elradfmw"
logger.warning("permission error")
if g_max_connect < 1:
g_max_connect =1
logger.warning("the allowed connecting could not smaller than 1")
if os.path.exists(g_dir) is False:
os.makedirs(g_dir)
logger.info("create dir : " + g_dir)
def run():
global g_user
global g_password
global g_dir
global g_port
global g_banonymous
global g_hided
global g_bautostartup
global g_max_connect
global g_permission
logger.info("currnt dir : " +g_dir)
print ("currnt dir : " +g_dir)
try:
authorizer = DummyAuthorizer()
if g_banonymous:
authorizer.add_anonymous(g_dir,perm=g_permission)
else:
authorizer.add_user(g_user, g_password, g_dir, perm=g_permission)
handler = FTPHandler
handler.authorizer = authorizer
server = ThreadedFTPServer(("0.0.0.0", g_port), handler)
server.max_cons = g_max_connect
server.serve_forever()
except Exception,ex:
print ex
logger.error(ex)
os.system("pause")
return
def hide_wnd():
if platform.system() != "Windows":
return
global g_hided
if g_hided is False:
logger.info("windoes not hided")
return
whnd = ctypes.windll.kernel32.GetConsoleWindow()
if whnd != 0:
ctypes.windll.user32.ShowWindow(whnd, 0)
logger.debug("windows hided")
# ctypes.windll.kernel32.CloseHandle(whnd)
def auto_setup(t_bsetup):
if t_bsetup is False:
return
# doing something to setup with windows
if __name__ == "__main__":
if read_config():
hide_wnd()
run()