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相关推荐

  1. android客户端中间人攻击,Android 中间人攻击

    0x00 Android中间人攻击的思路就是劫持局域网中被攻击机器和服务器间的对话.被攻击机器和服务器表面上工作正常,实际上已经被中间人劫持.可以从一张图来明白这个过程. 受攻击主机发送的数据,首先经 ...

  2. asp.net运行机制

    ASP.NET运行机制原理 ---浏览器与IIS的交互过程 一.浏览器和服务器的交互原理 (一).浏览器和服务器交互的简单描述: 1.通俗描述:我们平时通过浏览器来访问网站,其实就相当于你通过浏览器去 ...

  3. ASP.NET 运行机制详解

    1.浏览器和服务器的交互原理 通俗描述:我们平时通过浏览器来访问网站,其实就相当于你通过浏览器去访问一台电脑上访问文件一样,只不过浏览器的访问请求是由被访问的电脑上的一个 WEB服务器软件来接收处理, ...

  4. 嵌入式Linux毕业论文题目,嵌入式毕业设计题目.doc

    嵌入式毕业设计题目 嵌入式毕业设计题目 篇一:嵌入式方向本科毕业论文题目 论文题目汇总表 2."题目类别":设计.论文: 3."题目性质":结合科研.结合生产. ...

  5. Webserver简易项目

    pr# Webserver组成部分 这个项目,粗略的看可以分为下面几个部分 建立socket通讯 服务器处理与客户端的IO 解析客户端的HTTP请求,并响应请求 建立socket通讯 Webserve ...

  6. c语言服务器制作,C语言写的简易实用的web服务器

    码农公社  210.net.cn  210是何含义?10月24日是程序员节,1024 =210.210既 210 之意. Apache在码农界是比较知名的,它也是目前最接地气.使用最广泛的Web服务器 ...

  7. Android作为HTTP服务器--NanoHTTPD源码分析

    欢迎访问个人开发论坛:http://jwzhangjie.com 专注盒子开发 @jwzhangjie NanoHTTPD源码以及解释 package com.jwzhangjie.shafa.mar ...

  8. 手写webserver服务器

    手写webserver服务器 文章目录 手写webserver服务器 前言 一.web server执行流程 组件说明 项目地址 二.代码实现 三. 效果展示 四.总结 前言 webserver 服务 ...

  9. (4.2.47.2)NanoHttpd手机服务器

    一.概述 二.Socket通信承载功能一览 三.核心实现NanoHTTPD 3.1 持有变量与构造函数 3.1.1 DefaultServerSocketFactory 服务SocketServer工 ...

  10. Android在如何建立一个WebServer

    今天老板交待任务最终完成了,感觉收获颇多,所以写一个关于它的记录,首先,看一下.老板的需求 需求: 希望移动端的用户标识(IMEI)和HTML页面的用户标识(Cookie)连接起来,当中HTML页面可 ...

最新文章

  1. C#机房重构-总结(二)
  2. .net Redis使用公共方法引用CSRedisCore
  3. ERROR: cannot launch node of type [pointcloud_to_laserscan/pointcloud_to_laserscan]
  4. mysql 设计两个主键都不可重复_18个MySQL面试题剖析(答案解析),听说身为程序员的你还没掌握...
  5. .net aspose.words 域加载图片_使用Python批量替换csdn文章的图片链接
  6. 亚马逊的vps多少钱一个月_如何查看您在亚马逊上花了多少钱
  7. html自动给图片加上水印 代码_如何给一千张图片去水印?还好我会python,100行代码轻松搞定...
  8. [EffectiveC++]item02:尽量以const,enum,inline代替#define
  9. Error: failed to unmarshal json. invalid character '\'' looking for beginning of value解决方案
  10. 全面开放运营3个月,百度揭秘Apollo最新技术创新
  11. jni java与c++交互返回三维数组jobjectArray
  12. 西工大计算机学院导师赵歆波,黎永前_西北工业大学研究生导师信息
  13. Edge浏览器运行卡顿怎么办 怎样让Edge浏览器速度更快
  14. 中国工业园区建设与运营市场发展状况与投资战略咨询报告2022-2028年
  15. 云服务器可以修改ip,云服务器的ip可以更换吗
  16. 计算机课故事作文,有趣的电脑课日记600字
  17. 游戏论坛项目设计分析
  18. 中国公司再获KDD两项最佳:松鼠AI拿下图深度学习研讨会最佳论文最佳学生论文...
  19. php 微信礼品卡,除了红包,你还可以用微信给亲朋好友发一张「礼品卡」
  20. 初识MySQL数据仓库

热门文章

  1. c语言验证5阶魔方矩阵,穷举法打印n阶魔方矩阵
  2. GAN手写体生成(MINIST)
  3. 无线RTU入库四川省地质灾害专业监测设备目录教程
  4. 记一次接口压力测试与性能调优
  5. PyTorch中文教程 | (1) PyTorch深度学习极速入门
  6. Windows下MySQL定时备份脚本
  7. 【MAC】手动下载安装docker
  8. 电脑录屏软件哪个好?高清流畅的录屏方法在这里!
  9. 基于STM32设计的数字电子秤
  10. 自定义竖着的SeekBar