twistedを使ってFTPサーバを立てる - Kivy Advent Calendar 2013
PCとAndroid端末とのファイルのやり取りには、USBつなぐのも面倒なのでDroidOverWifi (http://www.droidoverwifi.com/) なんかを使っています。いわばファイル編集機能特化のHTTPサーバです。
でもKivyLauncherだってtwistedが入っているんだし、それを使ってFTPサーバ作れないかなーと思って作ったのがこれです。
実行すると「IPアドレス:ポート番号」を表示してFTPサーバが立ち上り、FTPクライアントを使ってファイルのアップロード/ダウンロードができます(ポート番号は8021、PASVモードはオンにしてください)。
FFFTP (http://sourceforge.jp/projects/ffftp/) みたいなフォルダごと転送できるクライアントを使うと結構便利に使えます。
(/sdcard/kivy/ftpserver/)
android.txt | お約束 |
ipaddr.py | IPアドレスを表示させたいだけで作ったモジュール |
main.py | スクリプト本体 |
passwd.dat | パスワードファイル みちゃだめ |
(ipaddr.py)
import socket import fcntl import struct def get_ipaddr(): interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for iface in interfaces: ifreq = struct.pack('32s', iface) try: result = fcntl.ioctl(s.fileno(), 0x8915, ifreq) return socket.inet_ntoa(result[20:24]) except IOError: continue return None
(main.py)
from kivy import kivy_home_dir from kivy.app import App from kivy.uix.label import Label from kivy.support import install_twisted_reactor install_twisted_reactor() from twisted.protocols.ftp import FTPFactory, FTPRealm, FTPShell, IFTPShell from twisted.cred.portal import Portal from twisted.cred.checkers import AllowAnonymousAccess, FilePasswordDB, ANONYMOUS from twisted.internet import reactor from twisted.python.filepath import FilePath import ipaddr class MyFTPRealm(FTPRealm): HOME = kivy_home_dir #HOME = '/sdcard/kivy/' def requestAvatar(self, avatarId, mind, *interfaces): for iface in interfaces: if iface is IFTPShell: if avatarId is ANONYMOUS: avatar = FTPAnonymousShell(self.anonymousRoot) else: avatar = FTPShell(FilePath(self.HOME)) return IFTPShell, avatar, getattr(avatar, 'logout', lambda: None) raise NotImplementedError("Only IFTPShell interface is supported by this realm") class FTPServerApp(App): PORT = 8021 def build(self): portal = Portal( MyFTPRealm("./"), [AllowAnonymousAccess(), FilePasswordDB("passwd.dat")]) factory = FTPFactory(portal) reactor.listenTCP(self.PORT, factory) self.label = Label(text="FTP server started\n%s:%d" % (ipaddr.get_ipaddr(),self.PORT)) return self.label if __name__ == '__main__': FTPServerApp().run()
解説
最初にinstall_twisted_reactor()を実行すれば、Kivyアプリの開始・終了のタイミングでtwistedリアクタの開始・終了を行うようになります。
後はTwistedのプログラミングをすればOK。protocolクラスを使ってFTPサーバを組み立てていくわけですが、デフォルトのFTPRealmは「/home/(ユーザ名)」の下を公開しようとします。Androidはそんなディレクトリないので、サーバは立ち上がるけど認証後は550エラーを返し続けることになります。ここではMyFTPRealmを作って該当のメソッドを置き換えています。
FTPサーバで公開されるディレクトリ (kivy_home_dir) ですが、Androidだと「/sdcard/kivy/(アプリ名)/.kivy/」の下になります。ここはKivyのログファイルなどが書き込まれる場所なので無難といえば無難です。
とはいえ後でファイル移動させるのも面倒だし、どーせ自分しかLANにいませんよというなら「/sdcard/kivy/」や「/sdcard/」の下をどーんと公開しちゃうのもありかもしれません。
(何が起こっても一切責任持ちませんけど...)