使用NanoHttpd实现简易WebServer
0x00
在介绍使用NanoHttpd实现简易WebServer之前,我们首先熟悉下局域网Socket通信。一个Client工程,代码地址为https://github.com/jltxgcy/AppVulnerability/tree/master/MyClient。一个Server工程,代码地址为https://github.com/jltxgcy/AppVulnerability/tree/master/MyServer。
两个工程要在要同样的Wifi环境下,MyClient工程要修改连接目标的IP地址。如下:
clientSocket = new Socket("10.10.154.74",6100);
这个IP地址可以通过设置->关于手机->状态信息->IP地址获取。如下图:
具体的代码就不介绍了,大家自己分析。
0x01
下面介绍使用NanoHttpd实现简易WebServer。代码地址为https://github.com/jltxgcy/AppVulnerability/tree/master/NanoHttpD。
运行NanoHttpD后,在本机的UC浏览器输入http://127.0.0.1:8088,会返回it works。在其他连接相同wifi的手机浏览器上输入http://10.10.154.12(也就是运行NanoHttpD的手机IP),也会出现it works。
那么这个本地webServer是什么原理呢?
我们先看主Activity,代码如下:
public class MainActivity extends Activity {private SimpleServer server;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);server = new SimpleServer();try {// 因为程序模拟的是html放置在asset目录下,// 所以在这里存储一下AssetManager的指针。server.asset_mgr = this.getAssets();// 启动web服务server.start();Log.i("Httpd", "The server started.");} catch(IOException ioe) {Log.w("Httpd", "The server could not start.");}}......
}
创建了SimpleServer对象,然后调用了它的start方法。我们来看SimpleServer类的代码:
public class SimpleServer extends NanoHTTPD {AssetManager asset_mgr;public SimpleServer() {// 端口是8088,也就是说要通过http://127.0.0.1:8088来访当问super(8088);}public Response serve(String uri, Method method, Map<String, String> header,Map<String, String> parameters,Map<String, String> files){int len = 0; byte[] buffer = null;Log.d("jltxgcy", header.get("remote-addr"));// 默认传入的url是以“/”开头的,需要删除掉,否则就变成了绝对路径String file_name = uri.substring(1);// 默认的页面名称设定为index.htmlif(file_name.equalsIgnoreCase("")){file_name = "index.html";}try {//通过AssetManager直接打开文件进行读取操作InputStream in = asset_mgr.open(file_name, AssetManager.ACCESS_BUFFER);//假设单个网页文件大小的上限是1MBbuffer = new byte[1024*1024]; int temp=0;while((temp=in.read())!=-1){buffer[len]=(byte)temp; len++; }in.close(); } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 将读取到的文件内容返回给浏览器return new NanoHTTPD.Response(new String(buffer,0,len));}
}
SimpleServer继承了NanoHTTPD,server.start()实际上调用NanoHTTPD类的start方法。如下:
public void start() throws IOException {myServerSocket = new ServerSocket();myServerSocket.bind((hostname != null) ? new InetSocketAddress(hostname, myPort) : new InetSocketAddress(myPort));myThread = new Thread(new Runnable() {@Overridepublic void run() {do {try {final Socket finalAccept = myServerSocket.accept();registerConnection(finalAccept);finalAccept.setSoTimeout(SOCKET_READ_TIMEOUT);final InputStream inputStream = finalAccept.getInputStream();if (inputStream == null) {safeClose(finalAccept);unRegisterConnection(finalAccept);} else {asyncRunner.exec(new Runnable() {@Overridepublic void run() {OutputStream outputStream = null;try {outputStream = finalAccept.getOutputStream();TempFileManager tempFileManager = tempFileManagerFactory.create();HTTPSession session = new HTTPSession(tempFileManager, inputStream, outputStream, finalAccept.getInetAddress());while (!finalAccept.isClosed()) {session.execute();}} catch (Exception e) {// When the socket is closed by the client, we throw our own SocketException// to break the "keep alive" loop above.if (!(e instanceof SocketException && "NanoHttpd Shutdown".equals(e.getMessage()))) {e.printStackTrace();}} finally {safeClose(outputStream);safeClose(inputStream);safeClose(finalAccept);unRegisterConnection(finalAccept);}}});}} catch (IOException e) {}} while (!myServerSocket.isClosed());}});myThread.setDaemon(true);myThread.setName("NanoHttpd Main Listener");myThread.start();}
创建了一个Socket Server, myServerSocket.accept()阻塞等待连接,当在本机浏览器输入 http://127.0.0.1:8088,建立连接,接下来去处理这个连接,myThread线程会继续执行到session.execute。我们来看那这个函数的代码:
@Overridepublic void execute() throws IOException {try {// Read the first 8192 bytes.// The full header should fit in here.// Apache's default header limit is 8KB.// Do NOT assume that a single read will get the entire header at once!byte[] buf = new byte[BUFSIZE];splitbyte = 0;rlen = 0;{int read = -1;try {read = inputStream.read(buf, 0, BUFSIZE);} catch (Exception e) {safeClose(inputStream);safeClose(outputStream);throw new SocketException("NanoHttpd Shutdown");}if (read == -1) {// socket was been closedsafeClose(inputStream);safeClose(outputStream);throw new SocketException("NanoHttpd Shutdown");}while (read > 0) {rlen += read;splitbyte = findHeaderEnd(buf, rlen);if (splitbyte > 0)break;read = inputStream.read(buf, rlen, BUFSIZE - rlen);}}if (splitbyte < rlen) {ByteArrayInputStream splitInputStream = new ByteArrayInputStream(buf, splitbyte, rlen - splitbyte);SequenceInputStream sequenceInputStream = new SequenceInputStream(splitInputStream, inputStream);inputStream = sequenceInputStream;}parms = new HashMap<String, String>();if(null == headers) {headers = new HashMap<String, String>();}// Create a BufferedReader for parsing the header.BufferedReader hin = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, rlen)));// Decode the header into parms and header java propertiesMap<String, String> pre = new HashMap<String, String>();decodeHeader(hin, pre, parms, headers);method = Method.lookup(pre.get("method"));if (method == null) {throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Syntax error.");}uri = pre.get("uri");cookies = new CookieHandler(headers);// Ok, now do the serve()Response r = serve(this);if (r == null) {throw new ResponseException(Response.Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: Serve() returned a null response.");} else {cookies.unloadQueue(r);r.setRequestMethod(method);r.send(outputStream);}} catch (SocketException e) {// throw it out to close socket object (finalAccept)throw e;} catch (SocketTimeoutException ste) {throw ste;} catch (IOException ioe) {Response r = new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());r.send(outputStream);safeClose(outputStream);} catch (ResponseException re) {Response r = new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());r.send(outputStream);safeClose(outputStream);} finally {tempFileManager.clear();}}
这个函数解析 http://127.0.0.1:8088(数据来源于finalAccept.getInputStream()),然后调用了SimpleServer的serve方法,这个server方法返回的就是显示在浏览器中的内容。
我们根据调试,看一下public Response serve(String uri, Method method, Map<String, String> header, Map<String, String> parameters, Map<String, String> files),这些参数返回的值到底是多少?
url为/,method为GET,head为{accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,UC/145,plugin/1,alipay/un, accept-encoding=gzip, host=127.0.0.1:8088, accept-language=zh-CN, http-client-ip=127.0.0.1, cache-control=max-age=0, x-ucbrowser-ua=dv(Nexus 6);pr(UCBrowser/10.7.0.634);ov(Android 5.1.1);ss(411*683);pi(1440*2392);bt(UM);pm(1);bv(1);nm(0);im(0);sr(0);nt(2);, remote-addr=127.0.0.1, user-agent=Mozilla/5.0 (Linux; U; Android 5.1.1; zh-CN; Nexus 6 Build/LMY47Z) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 UCBrowser/10.7.0.634 U3/0.8.0 Mobile Safari/534.30, connection=keep-alive},parameters为{NanoHttpd.QUERY_STRING=null},files为{}。
如果请求的地址为http://127.0.0.1:8088/adv?d=1,则url为adv,parameter为{d=1, NanoHttpd.QUERY_STRING=d=1}。
使用NanoHttpd实现简易WebServer相关推荐
- android客户端中间人攻击,Android 中间人攻击
0x00 Android中间人攻击的思路就是劫持局域网中被攻击机器和服务器间的对话.被攻击机器和服务器表面上工作正常,实际上已经被中间人劫持.可以从一张图来明白这个过程. 受攻击主机发送的数据,首先经 ...
- asp.net运行机制
ASP.NET运行机制原理 ---浏览器与IIS的交互过程 一.浏览器和服务器的交互原理 (一).浏览器和服务器交互的简单描述: 1.通俗描述:我们平时通过浏览器来访问网站,其实就相当于你通过浏览器去 ...
- ASP.NET 运行机制详解
1.浏览器和服务器的交互原理 通俗描述:我们平时通过浏览器来访问网站,其实就相当于你通过浏览器去访问一台电脑上访问文件一样,只不过浏览器的访问请求是由被访问的电脑上的一个 WEB服务器软件来接收处理, ...
- 嵌入式Linux毕业论文题目,嵌入式毕业设计题目.doc
嵌入式毕业设计题目 嵌入式毕业设计题目 篇一:嵌入式方向本科毕业论文题目 论文题目汇总表 2."题目类别":设计.论文: 3."题目性质":结合科研.结合生产. ...
- Webserver简易项目
pr# Webserver组成部分 这个项目,粗略的看可以分为下面几个部分 建立socket通讯 服务器处理与客户端的IO 解析客户端的HTTP请求,并响应请求 建立socket通讯 Webserve ...
- c语言服务器制作,C语言写的简易实用的web服务器
码农公社 210.net.cn 210是何含义?10月24日是程序员节,1024 =210.210既 210 之意. Apache在码农界是比较知名的,它也是目前最接地气.使用最广泛的Web服务器 ...
- Android作为HTTP服务器--NanoHTTPD源码分析
欢迎访问个人开发论坛:http://jwzhangjie.com 专注盒子开发 @jwzhangjie NanoHTTPD源码以及解释 package com.jwzhangjie.shafa.mar ...
- 手写webserver服务器
手写webserver服务器 文章目录 手写webserver服务器 前言 一.web server执行流程 组件说明 项目地址 二.代码实现 三. 效果展示 四.总结 前言 webserver 服务 ...
- (4.2.47.2)NanoHttpd手机服务器
一.概述 二.Socket通信承载功能一览 三.核心实现NanoHTTPD 3.1 持有变量与构造函数 3.1.1 DefaultServerSocketFactory 服务SocketServer工 ...
- Android在如何建立一个WebServer
今天老板交待任务最终完成了,感觉收获颇多,所以写一个关于它的记录,首先,看一下.老板的需求 需求: 希望移动端的用户标识(IMEI)和HTML页面的用户标识(Cookie)连接起来,当中HTML页面可 ...
最新文章
- C#机房重构-总结(二)
- .net Redis使用公共方法引用CSRedisCore
- ERROR: cannot launch node of type [pointcloud_to_laserscan/pointcloud_to_laserscan]
- mysql 设计两个主键都不可重复_18个MySQL面试题剖析(答案解析),听说身为程序员的你还没掌握...
- .net aspose.words 域加载图片_使用Python批量替换csdn文章的图片链接
- 亚马逊的vps多少钱一个月_如何查看您在亚马逊上花了多少钱
- html自动给图片加上水印 代码_如何给一千张图片去水印?还好我会python,100行代码轻松搞定...
- [EffectiveC++]item02:尽量以const,enum,inline代替#define
- Error: failed to unmarshal json. invalid character '\'' looking for beginning of value解决方案
- 全面开放运营3个月,百度揭秘Apollo最新技术创新
- jni java与c++交互返回三维数组jobjectArray
- 西工大计算机学院导师赵歆波,黎永前_西北工业大学研究生导师信息
- Edge浏览器运行卡顿怎么办 怎样让Edge浏览器速度更快
- 中国工业园区建设与运营市场发展状况与投资战略咨询报告2022-2028年
- 云服务器可以修改ip,云服务器的ip可以更换吗
- 计算机课故事作文,有趣的电脑课日记600字
- 游戏论坛项目设计分析
- 中国公司再获KDD两项最佳:松鼠AI拿下图深度学习研讨会最佳论文最佳学生论文...
- php 微信礼品卡,除了红包,你还可以用微信给亲朋好友发一张「礼品卡」
- 初识MySQL数据仓库