Android基于SwiFTP开源库的FTP实现(FTP匿名登录)

FTP是基于FTP协议来实现文件的管理,理论上只要将协议逐个实现,就可以实现一个FTP的服务端了,但需要一些时间,而且还是个体力活。现在有了SwiFTP的开源库,只要对其稍加改造,就可以将手机快速变成一个FTP的服务器。这里提供一个SwiFTP的下载地址https://github.com/sparkleDai/swiftp

我们先来看看SwiFTP源码中实现的效果图:



前一个图是FTP的配置,后一个图是FTP服务器控制。这两个画面,一看就是一嘛黑的,老外貌似比较喜欢这种风格。下面是修改后的效果图。



修改后的FTP服务端只有一个启动/停止的按钮,其他的都采用默认设置。下面我们来看具体的修改步骤。

1、跳过配置画面

SwiFTP一开启就会跳到配置画面,经查代码,发现是在ServerControlActivity的OnResume中跳转过来的,所以只要想办法跳过去就可以了。要跳过去,有几种方式,最直接的就是屏蔽掉。不过,考虑到原来有配置画面,这里可能需要留一个口来增加设置,所以这里我增加了一个配置函数,将所需要的配置项配置成了默认项,代码如下。(我将ServerControlActivity改成了MainActivity)

MainActivity.java
	protected void onResume() {
		super.onResume();
		// If the required preferences are not present, launch the configuration
		// Activity.
		configSetting();
		if (!requiredSettingsDefined()) {
			launchCONFIG_KEYS();
		}
		UiUpdater.registerClient(handler);
		updateUi();
		// Register to receive wifi status broadcasts
		myLog.l(Log.DEBUG, "Registered for wifi updates");
		this.registerReceiver(wifiReceiver, new IntentFilter(
				WifiManager.WIFI_STATE_CHANGED_ACTION));
	}

	private void configSetting() {
		// Validation was successful, save the settings object
		SharedPreferences settings = getSharedPreferences(
				Defaults.getSettingsName(), Defaults.getSettingsMode());
		SharedPreferences.Editor editor = settings.edit();

		editor.putString(CONFIG_KEYS.USERNAME, Defaults.username);
		editor.putString(CONFIG_KEYS.PASSWORD, Defaults.password);
		editor.putInt(CONFIG_KEYS.PORTNUM, 2121);
		editor.putString(CONFIG_KEYS.CHROOTDIR, Defaults.chrootDir);
		editor.putBoolean(CONFIG_KEYS.ACCEPT_WIFI, Defaults.acceptWifi);
		editor.putBoolean(CONFIG_KEYS.ACCEPT_NET, Defaults.acceptNet);
		editor.putBoolean(CONFIG_KEYS.STAY_AWAKE, Defaults.stayAwake);
		editor.putBoolean(CONFIG_KEYS.IS_ANONYMOUS, Defaults.isAnonymous);
		editor.commit();
		
	}

CONFIG_KEYS.java
package com.sparkle.ftp;

public class CONFIG_KEYS {
	public final static String USERNAME = "username";
	public final static String PASSWORD = "password";
	public final static String PORTNUM = "portNum";
	public final static String CHROOTDIR = "chrootDir";
	public final static String ACCEPT_WIFI = "allowWifi";
	public final static String ACCEPT_NET = "allowNet";
	public final static String STAY_AWAKE = "stayAwake";
	public final static String IS_ANONYMOUS="isAnonymous";
}

Defaults.java部分代码
	protected static int inputBufferSize = 256;
	protected static int dataChunkSize = 65536;  // do file I/O in 64k chunks 
	protected static int sessionMonitorScrollBack = 10;
	protected static int serverLogScrollBack = 10;
	protected static int uiLogLevel = Defaults.release ? Log.INFO : Log.DEBUG;
	protected static int consoleLogLevel = Defaults.release ? Log.INFO : Log.DEBUG;
	protected static String settingsName = "FTP";
	public static String username = "Anonynous";
	public static String password = "";
	protected static int portNumber = 2121; 
//	protected static int ipRetrievalAttempts = 5;
	public static final int tcpConnectionBacklog = 5;
	public static final String chrootDir = Environment.getExternalStorageDirectory().getAbsolutePath();
	public static final boolean acceptWifi = true;
	public static final boolean acceptNet = false; // don't incur bandwidth charges
	public static final boolean stayAwake = false;
	public static final boolean isAnonymous=true;
	public static final int REMOTE_PROXY_PORT = 2222;
	public static final String STRING_ENCODING = "UTF-8";
	public static final int SO_TIMEOUT_MS = 30000; // socket timeout millis


注:
(1)、Activity的生命周期是OnCreate->OnStart->OnResume->OnPause->OnStop->OnDestory。在activity1跳转到另一个activity2后,如果跳转时activity1没有finish掉,那么activity2关闭跳后,activity1会从activity堆栈中重新唤醒,也就是会调用OnResume。所以在配置的activity中,如果没有配置,当点cancel,配置的activity虽然被关闭了,但是当回到服务控制的activity后,又激活了OnResume,然后判断配置的情况,如果不符合,又会启动配置的activity。所以会发现,如果没有配置,即使点cancel也没有作用,不知道的还以为中镖了。
(2)、SharedPreference是共享数据的一种方式,可以实现跨activity的数据共享,是一个轻量的存储方式,本质上是一个xml的key-value对。对其修改数据时,需要请求edit,然后修改数据,最后还要commit。这个和提交代码到git/svn等类似。
(3)、CONFIG_KEYS是将原来配置的activity中的一些key写到了这个类中。
(4)、Defaults中增加了username、password、isAnonymous。其中isAnonymous是为了实现FTP的匿名访问而增设的一个配置项。
(5)、由于手机内存中的文件不一定都能访问,所以FTP默认的目录设置到了SD卡中。在不同的设备中,对于SD卡的路径有所不同,所以采用了系统自带的函数来实现,即chrootDir = Environment.getExternalStorageDirectory().getAbsolutePath()。

2、实现匿名访问
现在将服务端跑起来后,已经可以正常访问了,不过每次访问的时候都会弹出用户名和密码的输入框,让人很烦,所以就想着法子的屏蔽掉。既然会弹出这个框,程序中肯定会有对应的判断项,经过查找,发现是在FTP中的PASS命令中实现的。所以对CmdPASS.java作了些修改,修改部分的代码如下。
public void run() {
		// User must have already executed a USER command to
		// populate the Account object's username
		myLog.l(Log.DEBUG, "Executing PASS");
		Context ctx = Globals.getContext();
		SharedPreferences settings = ctx.getSharedPreferences(
				Defaults.getSettingsName(), Defaults.getSettingsMode());
		boolean isAnonymous=settings.getBoolean(CONFIG_KEYS.IS_ANONYMOUS,false);
		if(isAnonymous)
		{
			sessionThread.writeString("230 Access granted\r\n");
			myLog.l(Log.INFO, "Anonymous visit!");
			sessionThread.authAttempt(true);
			return;
		}
		
		if(ctx == null) {
			// This will probably never happen, since the global 
			// context is configured by the Service
			myLog.l(Log.ERROR, "No global context in PASS\r\n");
		}
		
		String attemptPassword = getParameter(input, true); // silent
		String attemptUsername = sessionThread.account.getUsername();
		if(attemptUsername == null) {
			sessionThread.writeString("503 Must send USER first\r\n");
			return;
		}
	
		String username = settings.getString("username", null);
		String password = settings.getString("password", null);
		if(username == null || password == null) {
			myLog.l(Log.ERROR, "Username or password misconfigured");
			sessionThread.writeString("500 Internal error during authentication");
		} else if(username.equals(attemptUsername) && 
				password.equals(attemptPassword)) {
			sessionThread.writeString("230 Access granted\r\n");
			myLog.l(Log
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值