android 服务器 模板 android web服务器
在android上如何编写一个小型web服务器?
这个是前几年之前接触到的一个项目的需求,需要是android手机建立一个无线热点,其他设备连接热点后,访问网站,都跳转到android手机上热点提供的网站,所以就需要android手机端实现一个简易的web服务器,服务器的资源文件都存储在sd卡,并且可以更新。
废话不多说,这边把项目早期做的可行性研究的demo整理了下,开源出来。
这个小型web服务器很大一部分参考AndroidWebServ工程(https:///joinAero/AndroidWebServ),在此多谢。
刚刚百度了下,已经有很多大牛也实现了类似的功能,用的方法也基本一致。这边在大概介绍下用到的具体技术
1:创建一个ServerSocket
2:使用HttpService创建一个Http服务,并为这个http创建需要的HTTP请求执行器(用来响应客户端发过来的get,download,upload等请求)
3:接收通过ServerSocket过来的Socket请求,并将Socket映射到HttpService上,这样HttpService就会返回对应的数据到客户端,客户端就能浏览网页了
核心代码在org.join.ws.serv.WebServer上,这边摘取部分片段
// 创建服务器套接字 serverSocket = new ServerSocket(port); // 设置端口重用 serverSocket.setReuseAddress(true); // 创建HTTP协议处理器 BasicHttpProcessor httpproc = new BasicHttpProcessor(); // 增加HTTP协议拦截器 httpproc.addInterceptor(new ResponseDate()); httpproc.addInterceptor(new ResponseServer()); httpproc.addInterceptor(new ResponseContent()); httpproc.addInterceptor(new ResponseConnControl()); // 创建HTTP服务 HttpService httpService = new HttpService(httpproc, new DefaultConnectionReuseStrategy(), new DefaultHttpResponseFactory()); // 创建HTTP参数 HttpParams params = new BasicHttpParams(); params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000) .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false) .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "WebServer/1.1"); // 设置HTTP参数 httpService.setParams(params); // 创建HTTP请求执行器注册表 HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); // 增加HTTP请求执行器 reqistry.register(UrlPattern.DOWNLOAD, new HttpDownHandler(webRoot)); reqistry.register(UrlPattern.DELETE, new HttpDelHandler(webRoot)); reqistry.register(UrlPattern.UPLOAD, new HttpUpHandler(webRoot)); reqistry.register(UrlPattern.PROGRESS, new HttpProgressHandler()); reqistry.register(UrlPattern.BROWSE, new HttpFBHandler(webRoot)); // 设置HTTP请求执行器 httpService.setHandlerResolver(reqistry); // 回调通知服务开始 if (mListener != null) { mListener.onStarted(); } /* 循环接收各客户端 */ isLoop = true; while (isLoop && !Thread.interrupted()) { // 接收客户端套接字 Socket socket = serverSocket.accept(); // 绑定至服务器端HTTP连接 DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); conn.bind(socket, params); // 派送至WorkerThread处理请求 Thread t = new WorkerThread(httpService, conn, mListener); t.setDaemon(true); // 设为守护线程 pool.execute(t); // 执行 }
项目中还用到 一个比较重要的库,Jangod,这个库很强大,可以用来从文件或者从代码中加载html,并支持css,有兴趣的同学可以 继续研究下去。
另外还有一个问题,怎么样把客户端所有的http请求都引到我们的ServerSocket?这边就需要用到nat表了,前提是你手机root了
1:将所有对80端口的http请求都强制转换到我们的ServerSocket,命令如下
String cmd = "iptables -t nat -A PREROUTING -d 0.0.0.0/0 -p tcp --dport 80 -j DNAT --to-destination " +CommonUtil.getLocalIpAddress()+":" + Config.PORT;//192.168.43.1:7766";
2:将 所有对53端口的dns请求都强制装换到我们的dns请求端口,并实现dns的响应
String cmd53 = "iptables -t nat -A PREROUTING -d 0.0.0.0/0 -p udp --dport 53 -j DNAT --to-destination " +CommonUtil.getLocalIpAddress()+":" + Config.PORT_DNS;//192.168.43.1:7766";package org.join.ws.serv; import java.io.IOException; import .DatagramPacket; import .DatagramSocket; import .ServerSocket; import .Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.http.impl.DefaultConnectionReuseStrategy; import org.apache.http.impl.DefaultHttpResponseFactory; import org.apache.http.impl.DefaultHttpServerConnection; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpParams; import org.apache.http.protocol.BasicHttpProcessor; import org.apache.http.protocol.HttpRequestHandlerRegistry; import org.apache.http.protocol.HttpService; import org.apache.http.protocol.ResponseConnControl; import org.apache.http.protocol.ResponseContent; import org.apache.http.protocol.ResponseDate; import org.apache.http.protocol.ResponseServer; import org.join.ws.Constants.Config; import org.join.ws.serv.req.HttpDelHandler; import org.join.ws.serv.req.HttpDownHandler; import org.join.ws.serv.req.HttpFBHandler; import org.join.ws.serv.req.HttpProgressHandler; import org.join.ws.serv.req.HttpUpHandler; import org.join.ws.util.CommonUtil; /** * @brief DnsWeb服务类 * @author talkercenter */ public class DnsServer extends Thread { static final String TAG = "DnsServer"; static final boolean DEBUG = false || Config.DEV_MODE; byte[] requestBuffer = new byte[256]; byte[] responseBuffer = new byte[256]; byte[] ipBuffer = { (byte) 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x7c, 0x00, 0x04, (byte)0xc0, (byte)0xa8, 0x2b, 0x01 }; public static final int ERR_UNEXPECT = 0x0101; public static final int ERR_PORT_IN_USE = 0x0102; public static final int ERR_TEMP_NOT_FOUND = 0x0103; private int port; //private String webRoot; private DatagramSocket serverSocket; /* package */static boolean isLoop; private OnWebServListener mListener; //private ExecutorService pool; // 线程池 public DnsServer(int port, final String webRoot) { super(); this.port = port; //this.webRoot = webRoot; isLoop = false; //pool = Executors.newCachedThreadPool(); } @Override public void run() { try { // Decide if port is in use. if (CommonUtil.getSingleton().isLocalPortInUse(port)) { if (mListener != null) { mListener.onError(ERR_PORT_IN_USE); } return; } // 创建服务器套接字 serverSocket = new DatagramSocket(port); DatagramPacket requestPacket = new DatagramPacket(requestBuffer,requestBuffer.length); /* 循环接收各客户端 */ isLoop = true; while (isLoop && !Thread.interrupted()) { serverSocket.receive(requestPacket); int requestLength = requestPacket.getLength(); System.arraycopy(requestBuffer, 0, responseBuffer, 0, requestLength); System.arraycopy(ipBuffer, 0, responseBuffer, requestLength, ipBuffer.length); // 标志位 responseBuffer[2] = (byte) 0x81; responseBuffer[3] = (byte) 0x80; // 响应数 responseBuffer[6] = (byte) 0x00; responseBuffer[7] = (byte) 0x01; DatagramPacket response = new DatagramPacket(responseBuffer, requestLength + ipBuffer.length, requestPacket.getAddress(), requestPacket.getPort()); serverSocket.send(response); } } catch (IOException e) { if (isLoop) { // 以排除close造成的异常 // 回调通知服务出错 if (mListener != null) { mListener.onError(ERR_UNEXPECT); } if (DEBUG) e.printStackTrace(); isLoop = false; } } finally { try { if (serverSocket != null) { serverSocket.close(); } // 回调通知服务结束 if (mListener != null) { mListener.onStopped(); } } catch (Exception e) { } } } public void close() { isLoop = false; try { if (serverSocket != null) { serverSocket.close(); } } catch (Exception e) { } } public interface OnWebServListener { void onStarted(); void onStopped(); void onError(int code); } public void setOnWebServListener(OnWebServListener mListener) { this.mListener = mListener; } }
结束,完整代码请访问
https:///bobohuang1985/android-utils-api如何选择服务器(WEB服务器、DB数据库服务器)web服务器 数据库服务器
Windows系统-web服务器windows web服务器
Windows Server 搭建IIS Web服务器实战windows server 2012搭建web服务器
在服务器上安装Web服务器Apacheweb服务器的安装与配置
windows下安装apache web服务器iis的安装及web服务器配置
WEB服务器Nginx WINDOWS最简部署nginx web服务器
windows 下搭建web服务器安装centos系统centos7搭建web服务器