基于Android的服务器端程序实例

在 iOS 的 APP 中,每个程序都在自己的沙盒中运行,一旦程序删除了,应用的数据也就被清除了,所以大部分程序,需要保存数据的都会使用 iCloud 备份数据,但是如果是创作类的 APP,类似笔记之类的,如果要导出到电脑,就必须还要中转一次,非常麻烦。所以也有很多 APP 就开始内置了 FTP 服务器,一旦启动后,电脑只需要通过 FTP 客户端链接就可以访问 APP 内的数据了。

其实在Android中也有很多这些类似的 APP,为了方便和 PC 之间共享 APP 里的应用数据,也会有 FTP 或者WebDAV服务在 APP 里运行。但是Android不存在和 iOS 的那种沙盒问题,虽然 Android 也有沙盒。通常大部分的手机不会取得 root 权限,敏感的应用数据都会放在沙盒中,也就是 APP 内部数据目录,位于 /data/data/com.xxx.xx/ 中,可以通过 Context.getFilesDir() 获取到该路径,如果手机没有 root 权限,除了 APP 本身,谁也无法访问这里面的数据。但是 Android 可以选择将数据存放在外部沙盒中,也就是 APP 外部数据目录,可以通过Context.getExternalFilesDir() 获取到该路径,甚至还有其他歪门邪道的 APP 在外置存储里随便建立文件夹 ...

内置以服务器端运行方式和外部进行数据交换的 APP 有很多,比如多看阅读,Documents5 等等。

在实现上大部分都是启动 Socket 监听一个固定端口,然后处理 HTTP 请求,但是对于大部分 APP 码农,处理 HTTP 是一件非常麻烦的事情。要处理 Header,对 POST 和 GET 的处理,对文件上传和普通表单的处理等等,如果不借助第三方库,这个功能想要写好非常困难。

在第三方实现中有 AndroidAsync ,虽然没看过多看的源代码,但是估计十有八九也是采用了这个库。

不过它也可以作为客户端方式,作为监听服务方式运行使用方法非常简单:

AsyncHttpServer server = new AsyncHttpServer();
server.get("/", new HttpServerRequestCallback() {
  @Override
  public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
    response.send("Hello!!!");
  }
});
server.listen(5000);

对于大部分做过 WEB 的同学可能在提到服务器端程序时,肯定会想到 IIS 、Tomcat、Apache 这些。但是 IIS 是 Windows 平台的,IIS 所依赖的 HTTP.SYS 是系统驱动级别的,移植是不可能移植的,这辈子都不可能移植的。 Tomcat 是运行在 JVM 虚拟机上的 JavaEE 容器,Android 虽然也使用 JAVA 语言,但是其虚拟机是 ART(4.4以前是 Dalvik),Apache 是 C/C++ 开发的,移植到 Android 还是很有希望的。这个各位看官可以去网上找找相关的教程,Apache 如何交叉编译到 ARM,想做个伸手党也可以,很多已经编译好了的。

这里举个栗子说说如何在 Android 上运行 httpd for arm,可以先将编译好的 httpd 放入 raw 文件夹中,在 MainActivity 启动时判断是否在指定位置中,没有则释放。我通常是将其放在单独的服务中运行,这样就算 Activity 销毁了,服务还会在后台运行,这也是服务器必备的一个特性。

private File httpd;

@Override
public void onCreate() {
  super.onCreate();
  httpd = new File(getFilesDir(), "httpd");
  if (!httpd.exists()) {
    try {
      InputStream ins = getResources().openRawResource(R.raw.httpd);
      FileIOUtils.writeFileFromIS(httpd, ins);
      Runtime.getRuntime().exec("chmod 777 " + httpd.getAbsolutePath());
    } catch (Exception e) {
      Log.e(TAG, "onCreate: ", e);
    }
  }
}

在 Android 中有一个 Runtime 类,这个类主要是用来让 Android 应用程序可以与它所在的运行环境进行交互,可以直接通过调用 Runtime.getRuntime() 的静态方法来得到这个类的实例,再调用 exec 就可以执行命令,接下来我创建了一个二进制执行类,对其做了一个简单的封装。

public class BinExecuter {

  /**
   * 进程 PID
   */
  private int pid;

  /**
   * 可执行二进制文件路径
   */
  private String bin;

  /**
   * 启动参数
   */
  private String paras;

  /**
   * 进程实例
   */
  private Process process;

  /**
   * 获取 PID
   * @return
   */
  public int getPid() {
    return pid;
  }

  /**
   * 构造函数
   * @param bin 可执行二进制文件路径
   * @param paras 启动参数
   */
  public BinExecuter(String bin, String paras) {

    this.bin = bin;
    this.paras = paras;

  }

  /**
   * 启动进程
   */
  public void start() {

    try {
      process = Runtime.getRuntime().exec(bin + " " + paras);
      Field f = process.getClass().getDeclaredField("pid");
      f.setAccessible(true);
      pid = f.getInt(process);
      f.setAccessible(false);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  /**
   * 结束进程
   */
  public void stop() {
    if (pid > 0) {
      try {
        Runtime.getRuntime().exec("kill -9 " + pid);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
  }
}

但是这还是不够的,像 httpd 这类程序,启动后,控制台会有输出。例如有客户端请求了某个 url,或者出现什么错误,都会显示在控制台上。Android 上是没有控制台窗口的,那么如何捕捉控制台输出呢,简单,重定向输出到输入流中即可。

InputStream outs = process.getInputStream();
InputStreamReader isrout = new InputStreamReader(outs);
BufferedReader brout = new BufferedReader(isrout);
String line;
try {
  while ((line = brout.readLine()) != null) {
    log.d(line);
  }
} catch (Exception ex) {
  ex.printStackTrace();
}

注意了,这里有个大歪鹅(while),主线程会被阻塞的,启动另外的线程就行了,改造这个类,增加控制台输出的监听,可以让它变稍微强大一点。

/** author:yahch**/
public interface BinExecuteCallback {
  void onConsoleResponse(String text);
}

private BinExecuteCallback binExecuteCallback;

public void setBinExecuteCallback(BinExecuteCallback binExecuteCallback) {
  this.binExecuteCallback = binExecuteCallback;
}

在前段时间我开发的一个 Aria2 服务端中的对应用法如下:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
  if (intent != null) {
    ariaConfig = (AriaConfig) intent.getSerializableExtra("config");
    if (ariaConfig != null) {
      Log.d(TAG, ariaConfig.toString());
      binExecuter = new BinExecuter(fileAria2c.getAbsolutePath(), ariaConfig.toString());
      binExecuter.setBinExecuteCallback(new BinExecuter.BinExecuteCallback() {
        @Override
        public void onConsoleResponse(String text) {
          sendMessage(ARIA2_SERVICE_BIN_CONSOLE, text);
        }
      });
    }
  } else {
    stopSelf();
  }
  return super.onStartCommand(intent, flags, startId);
}

private void sendMessage(String name, String message) {
  MessageEvent genericEvent = new MessageEvent(name, message);
  EventBus.getDefault().post(genericEvent);
}

通过 EventBus 把服务中截取的控制台消息抛到 Activity 中,当然也可以使用广播,我觉得 EventBus 还是要好用些。

现在 GO 语言也百花齐放,GO 天生就是为了服务端而生,而且跨平台能力特别强大,在 Github 上已经有很多程序编译为了 ARM 版本的,像 frp、caddy、filebrowser 这些,都可以移植在 Android 上,我们要做的,就是给他一个壳,控制它运行和停止,以及配置些参数。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android解析服务器端发来的xml数据示例

    Android跟服务器交互数据,有时数据量大时,就需要以xml形式的交互数据.这里来实现服务器给Android客户端发送xml数据,Android客户端解析. 服务器端我使用dom4j第三方包来组织xml数据,大家可自行百度下载.而Android客户端则使用 XmlPullParser来解析xml数据. 服务器端代码: 复制代码 代码如下: package servlet; import java.io.IOException; import java.io.PrintWriter; impor

  • android客户端从服务器端获取json数据并解析的实现代码

    首先客户端从服务器端获取json数据 1.利用HttpUrlConnection 复制代码 代码如下: /**      * 从指定的URL中获取数组      * @param urlPath      * @return      * @throws Exception      */     public static String readParse(String urlPath) throws Exception {                  ByteArrayOutputSt

  • Android客户端post请求服务器端实例

    Android客户端请求服务器端的详细解释 1. Android客户端与服务器端通信方式: Android与服务器通信通常采用HTTP通信方式和Socket通信方式,而HTTP通信方式又分get和post两种方式. 2. 解析服务器端返回数据的解释: (1).对于服务器端来说,返回给客户端的数据格式一般分为html.xml和json这三种格式. (2). JSON(Javascript Object Notation)是一种轻量级的数据交换格式,相比于xml这种数据交换格式来说,因为解析xml比

  • Android连接服务器端的Socket的实例代码

    废话不多说了,直接给大家贴代码了,具体代码如下所述: package com.exa mple.esp8266; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import android.app.Activity; import android.os.Bundle; i

  • Android实现蓝牙客户端与服务器端通信示例

    一.首先说明:蓝牙通信必须用手机测试,因为avd里没有相关的硬件,会报错! 好了,看看最后的效果图:   二.概述: 1.判断是否支持Bluetooth BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if(bluetoothAdapter == null) { //the device doesn't support bluetooth } else { //the device support

  • 基于Android的服务器端程序实例

    在 iOS 的 APP 中,每个程序都在自己的沙盒中运行,一旦程序删除了,应用的数据也就被清除了,所以大部分程序,需要保存数据的都会使用 iCloud 备份数据,但是如果是创作类的 APP,类似笔记之类的,如果要导出到电脑,就必须还要中转一次,非常麻烦.所以也有很多 APP 就开始内置了 FTP 服务器,一旦启动后,电脑只需要通过 FTP 客户端链接就可以访问 APP 内的数据了. 其实在Android中也有很多这些类似的 APP,为了方便和 PC 之间共享 APP 里的应用数据,也会有 FTP

  • Java实现基于TCP的通讯程序实例解析

    Java中的TCP通信程序 TCP可以实现两台计算机之间的数据交互通信的两端,要严格区分客户端与服务端 两端通信时的步骤: 1.服务端程序,需要事先启动,等待客户端连接 2.客户端主动连接服务器端,才能成功通信,服务器端不可以主动链接客户端 在java中两个类用于实现TCP通信程序: 客户端: java.net.Socket 类表示.创建 Socket 对象,向服务端发出连接请求,服务端响应请求,两者建 立连接开始通信. 服务端: java.net.ServerSocket 类表示.创建 Ser

  • 基于Android studio3.6的JNI教程之opencv实例详解

    基本环境: Android studio3.6 NDK:r14b(尽量使用该版本) Opencv3.4.1 android sdk (1)新建工程OpenCVDemo,选择,一定要选择Native c++类型,最后要选c++14支持. (2)File->Project Structure->SDK Location,设置这3个路径,NDK选择r14b. (3)任意找一张图片,复制到res/drawable. (4)修改布局文件res/layout/ activity_main.xml <

  • Windows下使用Dev-C++开发基于pthread.h的多线程程序实例

    一.下载Windows版本的pthread 目前最新版本是:pthreads-w32-2-9-1-release.zip. 二.解压pthread到指定目录 我选择的目录是:E:\DEV-CPP\Pthread 完成后,该目录会多出三个文件夹:Pre-built.2,pthreads.2,QueueUserAPCEx. 三.配置Dev-C++编译选项 1)点击"工具"→"编译选项"→"目录"→"c++包含文件",浏览到刚才解压

  • Android基于HttpUrlConnection类的文件下载实例代码

    废话不多说了,直接给大家贴代码了,具体代码如所示: /** * get方法的文件下载 * <p> * 特别说明 android中的progressBar是google唯一的做了处理的可以在子线程中更新UI的控件 * * @param path */ private void httpDown(final String path) { new Thread() { @Override public void run() { URL url; HttpURLConnection connectio

  • Android获取应用程序大小和缓存的实例代码

    info package com.qin.appsize; import android.content.Intent; import android.graphics.drawable.Drawable; //Model类 ,用来存储应用程序信息 public class AppInfo { private String appLabel; //应用程序标签 private Drawable appIcon ; //应用程序图像 private Intent intent ; //启动应用程序

  • 基于Python的Android图形解锁程序详解

    安卓手机的图形锁是3x3的点阵,按次序连接数个点从而达到锁定/解锁的功能.最少需要连接4个点,最多能连接9个点.网上也有暴力删除手机图形锁的方法,即直接干掉图形锁功能.但假如你想进入别人的手机,但又不想引起其警觉的话--你可以参考一下本文(前提条件:手机需要root,而且打开调试模式.一般来讲,如果用过诸如"豌豆荚手机助手"."360手机助手"一类的软件,都会被要求打开调试模式的.如果要删除手机内置软件,则需要将手机root). 首先科普一下,安卓手机是如何标记这9

  • 基于Python socket的端口扫描程序实例代码

    本文研究的主要是Python的端口扫描程序,具体实例代码如下. 先来看看第一个端口扫描程序代码,获取本机的IP和端口号: import socket def get_my_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr,port

  • Android五子棋游戏程序完整实例分析

    最近学习了五子棋的课程,感觉挺不错.然后自己写了个关于五子棋的android程序,从中还是能够学习到很多东西的.现在我们开始今天五子棋程序的编写历程.程序的源码请参见友情链接: 好了,我们现在开始一步步的构建出项目来,首先是如下的项目结构图: 运行的效果图: 一些前期做准备的代码 1. 主活动类MainActivity,在菜单中加入了再来一局的功能: public class MainActivity extends AppCompatActivity { private ChessBoardV

随机推荐