不管工作中還是其他場合,經常會有文件分享的需求,比如自己下了一個4GB的游戲,同事下了一個800MB的軟件,其他人如果也需要這些文件,顯然直接分享是最快捷、最方便、最環保的方式了,如果再重新下,既浪費時間,又浪費電。Windows自帶了文件夾共享的功能,不過這玩意兒,至今我還沒仔細的去折騰過,也沒搞明白原理,我一直使用FTP來分享文件,如果有需要的話再弄個HTTP服務也足夠應付了,我的目的僅僅只是文件分享,簡單、易用是我主要關注的點。
反復可恥
這種需求必然是非常普遍的,解決方法也是多種多樣。比如飛鴿傳書、QQ,或者各種局域網通信軟件以及網盤都可以,不過這些都需要點對點的操作,也就是說對方需要什么文件,你就要把該文件發送過去,多一個人就需要多發一次,不能重用,對於程序員來說,不能接受,反復可恥!我覺得,文件服務器更符合這種需求,目前已經有很多成熟的軟件可以方便的實現這種需求,比如,FTP可以選擇FileZilla,HTTP可以選擇Apache、Nginx。當然,成熟意味着軟件更復雜,更大的學習成本、更多磁盤占用,這要看你的需求的復雜程度。
折騰至死
好了,我需要說明,我是個喜歡折騰的人,將一件看起來復雜、學習成本高的事情,折騰到簡單、易用是我的終極愛好,這篇文章正是這種折騰后的產物,希望直接達到目的的,成熟的軟件是你最好的歸宿。喜歡折騰,換種程序員喜歡的說法是,我熱衷於把復雜的實現,隱藏在良好命名的接口下。再換種通俗點的說法,汽車內部構造精良、結構復雜,而你只需要通過操作方向盤、剎車以及油門,就可以很好的操控它,這都歸功於這些接口的友好實現。
同樣的事情,只需要一遍就好。在平時寫代碼,也是這樣。如果我需要別人提供的一個接口,那我希望這個接口使用起來盡量簡單,我只需要知道調用什么接口、傳什么參數就行。我自己寫代碼,一定嚴格按照這種思路,我不認為使用者需要關注我是如何實現的,那是我的問題,使用者需要關注的是這個接口是干什么的、需要什么參數、可能返回的結果以及可能拋出的錯誤,分工明確,減少不必要的溝通。
我在前面一遍文章中有提到Python--導出指定文件夾中as文件的完全限定類名,好處我就不多說了,一個字,性感!很巧的是,我在折騰這個文件分享的功能時,遇到了他,借着這個機會,又復習了一遍HTTP和FTP方面的內容。
Python版HTTP服務器
閑話少說,首先確保裝了Python,我裝的是2.x版本,對了,我的操作系統是WIN7,其實對於Python來說,什么操作系統並不重要。Python內置了一個簡單的HTTP服務器,只需要在命令行下面敲一行命令,一個HTTP服務器就起來了:
python -m SimpleHTTPServer 80
后面的80端口是可選的,不填會采用缺省端口8000。注意,這會將當前所在的文件夾設置為默認的Web目錄,試着在瀏覽器敲入本機地址:
http://localhost:80
如果當前文件夾有index.html文件,會默認顯示該文件,否則,會以文件列表的形式顯示目錄下所有文件。這樣已經實現了最基本的文件分享的目的,你可以做成一個腳本,再建立一個快捷方式,就可以很方便的啟動文件分享了。如果有更多需求,完全可以根據自己需要定制,具體的請參見官方文檔SimpleHTTPServer,或者直接看源碼。我拷貝一段,方便參考:
import SimpleHTTPServer
import SocketServer
PORT = 8000
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
Python版FTP服務器
看到這里,默認你已經安裝了Python,不過你還需要安裝另外一個好用的工具。你知道,當需要找Chrome插件的時候,會去Google的WebStore;當需要找Firefox應用的時候,會去Mozilla的Add-ons;當你需要找Python組件的時候,你需要pip:A tool for installing and managing Python packages,安裝方法就不介紹了。
Python沒有內置一個直接可以用的FTP服務器,所以需要第三方組件的支持,我找到的這個組件叫pyftpdlib,首先安裝:
pip install pyftpdlib
安裝完后,和HTTP服器類似,執行以下命令就可以啟動一個FTP服務器了:
python -m pyftpdlib -p 21
后面的21端口依然是可選的,不填會隨機一個,被占用的端口將跳過。在瀏覽器敲入本機地址:
ftp://localhost:21
這時候,是匿名訪問,也就是用戶名是anonymous,密碼為空,如果想要控制訪問權限,你需要自己定制服務器,具體的可以參看pyftpdlib Tutorial,我這里拷貝過來一段作為介紹:
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
def main():
# Instantiate a dummy authorizer for managing 'virtual' users
authorizer = DummyAuthorizer()
# Define a new user having full r/w permissions and a read-only
# anonymous user
authorizer.add_user('user', '12345', '.', perm='elradfmwM')
authorizer.add_anonymous(os.getcwd())
# Instantiate FTP handler class
handler = FTPHandler
handler.authorizer = authorizer
# Define a customized banner (string returned when client connects)
handler.banner = "pyftpdlib based ftpd ready."
# Specify a masquerade address and the range of ports to use for
# passive connections. Decomment in case you're behind a NAT.
#handler.masquerade_address = '151.25.42.11'
#handler.passive_ports = range(60000, 65535)
# Instantiate FTP server class and listen on 0.0.0.0:2121
address = ('', 2121)
server = FTPServer(address, handler)
# set a limit for connections
server.max_cons = 256
server.max_cons_per_ip = 5
# start ftp server
server.serve_forever()
if __name__ == '__main__':
main()
只看代碼應該基本知道該怎么用了,add_user顯然是添加用戶,2121是指定端口,當然也可以隨機,還有最大連接數max_cons,每個ip最大連接限制,更多的接口建議直接看docstrings。
后記
Python第三方組件就是個大寶庫,基本上我自己遇到的大部分問題都可以在這里面找到解決文案。同時,建議喜歡折騰的程序員,甚至沒有程序背景的IT人員,都嘗試學習一下這門語言,這對解決問題的能力以及思維的鍛煉都有莫大裨益。