zoukankan      html  css  js  c++  java
  • 手机服务器微架构设计与实现 之 http server

    手机服务器微架构设计与实现 之 http server

    ·应用

     

     

    ·传输协议和应用层协议概念

    TCP

     UDP

     TCP和UDP选择

    三次握手(客户端与服务器端建立连接)/四次挥手(断开连接)过程图

     

    ·java Socket 基础

     

    ·Get 与 Post 协议格式

     

    ·开发真机与模拟器网络调试工具与配置

     真机:开发机和真机处于同一网段下即可

     模拟器:

    ·关键代码

      1 package com.example.lifen.simplehttpserver;
      2 
      3 import android.util.Log;
      4 
      5 import java.io.IOException;
      6 import java.io.InputStream;
      7 import java.net.InetSocketAddress;
      8 import java.net.ServerSocket;
      9 import java.net.Socket;
     10 import java.util.HashSet;
     11 import java.util.concurrent.ExecutorService;
     12 import java.util.concurrent.Executors;
     13 
     14 /**
     15  * Created by LiFen on 2017/12/27.
     16  */
     17 
     18 public class SimpleHttpServer {
     19     private static final String TAG = "SimpleHttpServer";
     20     private final WebConfiguration webConfig;
     21     private final ExecutorService threadPool;//线程池
     22     private final HashSet<IRsourceUriHandler> resourceUriHandlers;
     23     private boolean isEnable;
     24     private ServerSocket socket;
     25 
     26     public SimpleHttpServer(WebConfiguration webConfig){
     27         this.webConfig = webConfig;
     28         threadPool = Executors.newCachedThreadPool();
     29         resourceUriHandlers = new HashSet<>();
     30     }
     31 
     32     public void registerResourceHandler(IRsourceUriHandler iRsourceUriHandler){
     33         resourceUriHandlers.add(iRsourceUriHandler);
     34     }
     35 
     36     /**
     37      * 启动Server(异步)
     38      */
     39     public void startAsync(){
     40         isEnable = true;
     41         new Thread(new Runnable() {
     42             @Override
     43             public void run() {
     44                 doProcSync();
     45             }
     46         }).start();
     47     }
     48 
     49     /**
     50      * 停止Server(异步)
     51      */
     52     public void stopAsync() {
     53         if(!isEnable){
     54             return;
     55         }
     56         isEnable = false;
     57         try {
     58             socket.close();
     59         } catch (IOException e) {
     60             e.printStackTrace();
     61         }
     62         socket = null;
     63     }
     64 
     65     private void doProcSync() {
     66         Log.d(TAG, "doProcSync() called");
     67         try {
     68             InetSocketAddress socketAddr = new InetSocketAddress(webConfig.getPort());
     69             socket = new ServerSocket();
     70             socket.bind(socketAddr);
     71             while(isEnable){
     72                 final Socket remotePeer = socket.accept();
     73                 threadPool.submit(new Runnable() {
     74                     @Override
     75                     public void run() {
     76                         onAcceptRemotePeer(remotePeer);
     77                     }
     78                 });
     79             }
     80         } catch (IOException e) {
     81             Log.e(TAG, "doProcSync: e ", e);
     82         }
     83     }
     84 
     85     /**
     86      * 一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成
     87      * @param remotePeer
     88      */
     89     private void onAcceptRemotePeer(Socket remotePeer) {
     90         Log.d(TAG, "onAcceptRemotePeer() called with: remotePeer.getRemoteSocketAddress() = [" + remotePeer.getRemoteSocketAddress() + "]");
     91         HttpContext  httpContext = new HttpContext();
     92         try {
     93 //            remotePeer.getOutputStream().write("congratulations, connected success".getBytes());
     94             httpContext.setUnderlySocket(remotePeer);
     95             InputStream nis = remotePeer.getInputStream();
     96             String headerLine = null;
     97             String readLine = StreamToolkit.readLine(nis);//http请求行(request line)1
     98             Log.i(TAG, "http 1 请求行  readLine =" + readLine);
     99             //测试请求行结果 readLine =POST /get/?key=dddd&sss=123456 HTTP/1.1
    100             httpContext.setType(readLine.split(" ")[0]);
    101             String resourceUri = headerLine = readLine.split(" ")[1];
    102             Log.i(TAG, "地址 =" + headerLine);
    103             while ((headerLine = StreamToolkit.readLine(nis)) != null) {//http请求头部(header)2
    104 
    105                 if (headerLine.equals("
    ")) {//http请求空行3
    106                     Log.i(TAG, "http 3 请求头部 /r/n ");
    107                     break;
    108                 }
    109                 Log.i(TAG, "http 2 请求头部 headerLine = " + headerLine);
    110                 String[] pair = headerLine.split(": ");
    111                 if (pair.length > 1) {
    112                     httpContext.addRequestHeader(pair[0], pair[1]);
    113                 }
    114             }
    115 
    116             for (IRsourceUriHandler handler : resourceUriHandlers) {
    117                 if (!handler.accept(resourceUri)) {
    118                     continue;
    119                 }
    120                 handler.postHandle(resourceUri, httpContext);//http请求数据4
    121             }
    122         } catch (IOException e) {
    123             Log.e("spy",e.toString());
    124         }finally {//只要流或socket不关闭,浏览器就收不到信息
    125             try {
    126                 remotePeer.close();
    127             } catch (IOException e) {
    128                 e.printStackTrace();
    129             }
    130         }
    131     }
    132 }
     1 package com.example.lifen.simplehttpserver;
     2 
     3 import android.graphics.Bitmap;
     4 import android.graphics.BitmapFactory;
     5 import android.os.Bundle;
     6 import android.support.v7.app.AppCompatActivity;
     7 import android.widget.ImageView;
     8 
     9 public class MainActivity extends AppCompatActivity {
    10 
    11     private SimpleHttpServer shs;
    12     private ImageView imageView;
    13 
    14     @Override
    15     protected void onCreate(Bundle savedInstanceState) {
    16         super.onCreate(savedInstanceState);
    17         setContentView(R.layout.activity_main);
    18         imageView = (ImageView) findViewById(R.id.imageView);
    19 
    20         WebConfiguration wc = new WebConfiguration();
    21         wc.setPort(8088);
    22         wc.setMaxParallels(50);
    23 
    24         shs = new SimpleHttpServer(wc);
    25         /*
    26         向 shs 中添加 IRsourceUriHander 实例
    27          */
    28         shs.registerResourceHandler(new ResourceInAssetsHandler(this));
    29         shs.registerResourceHandler(new UploadImageHandler(this){
    30             @Override
    31             public void onImageLoaded(final String path) {//重写onImageLoaded方法 在UiTread 主线程中更新Ui
    32                 runOnUiThread(new Runnable() {
    33                     @Override
    34                     public void run() {
    35                         Bitmap bitmap = BitmapFactory.decodeFile(path);
    36                         imageView.setImageBitmap(bitmap);
    37                     }
    38                 });
    39             }
    40         });
    41 
    42         shs.startAsync();
    43     }
    44 
    45     @Override
    46     protected void onDestroy() {
    47         super.onDestroy();
    48         shs.stopAsync();
    49     }
    50 }
     1 package com.example.lifen.simplehttpserver;
     2 
     3 import android.content.Context;
     4 import android.util.Log;
     5 
     6 import java.io.IOException;
     7 import java.io.InputStream;
     8 import java.io.OutputStream;
     9 import java.io.PrintStream;
    10 
    11 /**
    12  * Created by LiFen on 2017/12/29.
    13  */
    14 
    15 public class ResourceInAssetsHandler implements IRsourceUriHandler {
    16     private static final String TAG = "ResourceInAssetsHandler";
    17     private String acceptPrefix = "/static/";
    18     private Context context;
    19 
    20     public ResourceInAssetsHandler(Context context){
    21         this.context = context;
    22     }
    23 
    24     @Override
    25     public boolean accept(String uri) {
    26         /*
    27         判断uri 是否以 “/static/" 开始
    28          */
    29         return uri.startsWith(acceptPrefix);
    30     }
    31 
    32     @Override
    33     public void postHandle(String uri, HttpContext httpContext) throws IOException{
    34         Log.d(TAG, "postHandle() called with: uri = [" + uri + "], httpContext = [" + httpContext + "]");
    35         /*
    36         截取assets 文件夹下静态网页相对路径
    37          */
    38         int startIndex = acceptPrefix.length();
    39         String assetsPath = uri.substring(startIndex);
    40         Log.i(TAG, "assetsPath: " + assetsPath);
    41 
    42         /*
    43         打开静态网页 返回一个输入流 转化为 byte[]
    44          */
    45         InputStream inputStream = context.getAssets().open(assetsPath);//打开文件 返回一个输入流
    46         byte[] raw = StreamToolkit.readRawFromStream(inputStream);
    47         Log.i(TAG, "assetsPath "+ "raw =" + raw.length);
    48         inputStream.close();
    49 
    50         OutputStream outputStream = httpContext.getUnderlySocket().getOutputStream();//获取当前Socket的输出流
    51         PrintStream printWriter = new PrintStream(outputStream);//输出符合http协议的信息给浏览器
    52         printWriter.println("HTTP/1.1 200 OK");
    53         printWriter.println("Content-Length:" + raw.length);
    54 
    55         if(assetsPath.endsWith(".html")){
    56             printWriter.println("Content-Type:text/html");
    57         }else if(assetsPath.endsWith(".js")){
    58             printWriter.println("Content-Type:text/js");
    59         }else if(assetsPath.endsWith(".css")){
    60             printWriter.println("Content-Type:text/css");
    61         }else if(assetsPath.endsWith(".jpg")){
    62             printWriter.println("Content-Type:text/jpg");
    63         }else if(assetsPath.endsWith(".png")){
    64             printWriter.println("Content-Type:text/png");
    65         }
    66         printWriter.println();
    67 
    68         printWriter.write(raw);
    69         Log.i(TAG, "postHandle: over");
    70     }
    71 }
     1 package com.example.lifen.simplehttpserver;
     2 
     3 import android.app.Activity;
     4 import android.os.Environment;
     5 import android.util.Log;
     6 
     7 import java.io.File;
     8 import java.io.FileOutputStream;
     9 import java.io.IOException;
    10 import java.io.InputStream;
    11 import java.io.OutputStream;
    12 import java.io.PrintWriter;
    13 
    14 
    15 /**
    16  * Created by LiFen on 2017/12/30.
    17  */
    18 
    19 class UploadImageHandler implements IRsourceUriHandler {
    20     private static final String TAG = "UploadImageHandler";
    21     String acceptPrefix = "/image/";
    22     Activity activity;
    23 
    24     public UploadImageHandler(Activity activity){
    25         this.activity = activity;
    26     }
    27 
    28     @Override
    29     public boolean accept(String uri) {
    30         return uri.startsWith(acceptPrefix);
    31     }
    32 
    33     @Override
    34     public void postHandle(String uri, HttpContext httpContext) throws IOException {
    35         long totalLength = Long.parseLong(httpContext.getRequestHeaderValue("Content-Length").trim());
    36         /*
    37         将 接收到的 图片存储到本机 SD卡目录下
    38          */
    39         File file = new File(Environment.getExternalStorageDirectory(),
    40                 "tmpFile.jpg");
    41         Log.i(TAG, "postHandle: " +"totalLength=" + totalLength + " file    getPath=" + file.getPath() );
    42         if(file.exists()){
    43             file.delete();
    44         }
    45         byte[] buffer = new byte[10240];
    46         int read;
    47         long nLeftLength = totalLength;
    48         FileOutputStream fileOutputStream = new FileOutputStream(file.getPath());//文件输出流
    49         InputStream inputStream = httpContext.getUnderlySocket().getInputStream();//从当前 Socket 中得到文件输入流
    50         while (nLeftLength > 0 && (read = inputStream.read(buffer)) > 0){//写到文件输出流中,即存储到SD 卡路径下
    51             fileOutputStream.write(buffer,0,read);
    52             nLeftLength -= read;
    53         }
    54         Log.i(TAG, "postHandle: close");
    55         fileOutputStream.close();
    56 
    57         /*
    58         从当前 Socket 中得到 文件输出流,将 符合http协议的信息 返回给浏览器
    59          */
    60         OutputStream outputStream = httpContext.getUnderlySocket().getOutputStream();
    61         PrintWriter printWriter = new PrintWriter(outputStream);
    62         printWriter.print("HTTP/1.1 200 OK");
    63         printWriter.println();
    64         /*
    65         记录图片存储的位置
    66          */
    67         onImageLoaded(file.getPath());
    68     }
    69 
    70     public void onImageLoaded(String path){
    71         Log.d(TAG, "onImageLoaded() called with: path = [" + path + "]");
    72     }
    73 }
     1 package com.example.lifen.simplehttpserver;
     2 
     3 import java.net.Socket;
     4 import java.util.HashMap;
     5 import java.util.Map;
     6 
     7 /**
     8  * Created by LiFen on 2017/12/28.
     9  */
    10 
    11 public class HttpContext {
    12     private Socket underlySocket;
    13     Map<String,String> heard = new HashMap<>();
    14     private String type;
    15 
    16     public void setUnderlySocket(Socket underlySocket){
    17         this.underlySocket = underlySocket;
    18     }
    19 
    20     public void addRequestHeader(String key,String value){
    21         heard.put(key,value);
    22     }
    23 
    24     public Socket getUnderlySocket(){
    25         return underlySocket;
    26     }
    27 
    28     public String getRequestHeaderValue(String key){
    29         return heard.get(key);
    30     }
    31 
    32     public String getType(){
    33         return type;
    34     }
    35 
    36     public void setType(String type){
    37         this.type = type;
    38     }
    39 }
     1 package com.example.lifen.simplehttpserver;
     2 
     3 import java.io.ByteArrayOutputStream;
     4 import java.io.IOException;
     5 import java.io.InputStream;
     6 
     7 /**
     8  * Created by LiFen on 2017/12/27.
     9  */
    10 
    11 public class StreamToolkit {
    12     public static final String readLine(InputStream nis) throws IOException {
    13         StringBuffer sb = new StringBuffer();
    14         int c1 = 0;
    15         int c2 = 0;
    16         while (c2 != -1 && !(c1 == '
    ' && c2 == '
    ')){
    17             c1 = c2;
    18             c2 = nis.read();
    19             sb.append((char)c2);
    20         }
    21         if(sb.length() == 0) {
    22             return null;
    23         }
    24         return sb.toString();
    25     }
    26 
    27     public static byte[] readRawFromStream(InputStream inputStream) throws IOException {
    28         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    29         byte[] buffer = new byte[10240];
    30         int read;
    31         while ((read = inputStream.read(buffer)) > 0){
    32             outputStream.write(buffer,0,read);
    33         }
    34         return outputStream.toByteArray();
    35     }
    36 
    37 }
     1 package com.example.lifen.simplehttpserver;
     2 
     3 /**
     4  * Created by LiFen on 2017/12/27.
     5  */
     6 
     7 public class WebConfiguration {
     8     /**
     9      * 端口
    10      */
    11     private int port;
    12     /**
    13      * 最大监听数
    14      */
    15     private int maxParallels;
    16 
    17     public int getPort() {
    18         return port;
    19     }
    20 
    21     public void setPort(int port) {
    22         this.port = port;
    23     }
    24 
    25     public int getMaxParallels() {
    26         return maxParallels;
    27     }
    28 
    29     public void setMaxParallels(int maxParallels) {
    30         this.maxParallels = maxParallels;
    31     }
    32 }
     1 package com.example.lifen.simplehttpserver;
     2 
     3 import java.io.IOException;
     4 
     5 /**
     6  * Created by LiFen on 2017/12/29.
     7  */
     8 
     9 public interface IRsourceUriHandler {
    10     boolean accept(String uri);
    11     void postHandle(String uri, HttpContext httpContext) throws IOException;
    12 }

     

    此项目github下载地址:

    https://github.com/li-fengjie/SimpleHttpServer

    win10正式版telnet不是内部或外部命令解决办法:

    https://jingyan.baidu.com/article/1e5468f9033a71484961b7d7.html

  • 相关阅读:
    java学习——内部类、匿名内部类
    Java中接口之间的继承
    Settings
    POM
    Maven指令
    Maven生命周期
    内部类
    Modules
    Simple Maven Project
    Maven概述
  • 原文地址:https://www.cnblogs.com/jxust-jiege666/p/8151326.html
Copyright © 2011-2022 走看看