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

  • 相关阅读:
    LeetCode 258 Add Digits
    LeetCode 231 Power of Two
    LeetCode 28 Implement strStr()
    LeetCode 26 Remove Duplicates from Sorted Array
    LeetCode 21 Merge Two Sorted Lists
    LeetCode 20 Valid Parentheses
    图形处理函数库 ImageTTFBBox
    php一些函数
    func_get_arg(),func_get_args()和func_num_args()的用法
    人生不是故事,人生是世故,摸爬滚打才不会辜负功名尘土
  • 原文地址:https://www.cnblogs.com/jxust-jiege666/p/8151326.html
Copyright © 2011-2022 走看看