Java实现Web Server

    

一直以来都是用Java写Web,但是呢,还没好好去了解实现一个Web Server,由此开始要逐步写出一个完善的WebServer,努力实现高性能的Web站点。

一、什么是Web服务器

网页服务器(Web server)一词有两个意思:

  1. 一台负责提供网页的电脑,主要是各种编程语言构建而成,通过HTTP协议传给客户端(一般是指网页浏览器)。
  2. 一个提供网页的服务器程序。

  虽然每个网页服务器程序有很多不同,但有一些共同的特点:每一个网页服务器程序都需要从网络接受HTTP request,然后提供HTTP response给请求者。HTTP回复一般包含一个HTML文件,有时也可以包含纯文本文件、图像或其他类型的文件。

二、简单了解下HTTP协议

 简介

  

  HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行之中,而且HTTP-NG(Next Generation of HTTP)的建议已经提出。

  HTTP协议的主要特点可概括如下:

  1.支持客户/服务器模式。

  2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

  3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

  4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

  5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTP协议详解-请求

http请求由三部分组成,分别是:请求行、消息报头、请求正文

  1、请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:Method Request-URI HTTP-Version CRLF  
其中 Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)。

  请求方法(所有方法全为大写)有多种,各个方法的解释如下:
    GET     请求获取Request-URI所标识的资源
    POST    在Request-URI所标识的资源后附加新的数据
    HEAD    请求获取由Request-URI所标识的资源的响应消息报头
    PUT     请求服务器存储一个资源,并用Request-URI作为其标识
    DELETE  请求服务器删除Request-URI所标识的资源
    TRACE   请求服务器回送收到的请求信息,主要用于测试或诊断
    CONNECT 保留将来使用
    OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
  应用举例:
    GET方法:在浏览器的地址栏中输入网址的方式访问网页时,浏览器采用GET方法向服务器获取资源,eg:GET /form.html HTTP/1.1 (CRLF)

    POST方法要求被请求服务器接受附在请求后面的数据,常用于提交表单。
    eg:POST /reg.jsp HTTP/ (CRLF)
    Accept:image/gif,image/x-xbit,... (CRLF)
    ...
    HOST:www.guet.edu.cn (CRLF)
    Content-Length:22 (CRLF)
    Connection:Keep-Alive (CRLF)
    Cache-Control:no-cache (CRLF)
    (CRLF)         //该CRLF表示消息报头已经结束,在此之前为消息报头
    user=jeffrey&pwd=1234  //此行以下为提交的数据

  HEAD方法与GET方法几乎是一样的,对于HEAD请求的回应部分来说,它的HTTP头部中包含的信息与通过GET请求所得到的信息是相同的。利用这个方法,不必传输整个资源内容,就可以得到Request-URI所标识的资源的信息。该方法常用于测试超链接的有效性,是否可以访问,以及最近是否更新。
  2、请求报头后述
  3、请求正文(略)

详情请转到另一篇博文:http://blog.csdn.net/gueter/article/details/1524447

三、实现自己WebServer

实现一个单线程的WebServer

  SingleThreadWebServer

    1、首先开启一个ServerSocket来监听9000端口

    2、一但获得一个连接请求,回复一条信息

 1 public class SingleThreadWebServer implements Runnable{
 2     protected int          serverPort   = 8080;
 3     protected ServerSocket serverSocket = null;
 4     protected Thread       runningThread= null;
 5
 6     public SingleThreadWebServer(int port){
 7         this.serverPort = port;
 8     }
 9
10     public void run(){
11         synchronized(this){
12             this.runningThread = Thread.currentThread();
13         }
14         openServerSocket();
15         System.out.println("Web服务器开启了");
16         while(true){
17             Socket clientSocket = null;
18             try {
19                 clientSocket = this.serverSocket.accept();
20             } catch (IOException e) {
21                 e.printStackTrace();
22             }
23             try {
24                 processClientRequest(clientSocket);
25             } catch (IOException e) {
26                 e.printStackTrace();
27             }
28         }
29
30     }
31
32     private void processClientRequest(Socket clientSocket)
33             throws IOException {
34         InputStream input  = clientSocket.getInputStream();
35         OutputStream output = clientSocket.getOutputStream();
36         long time = System.currentTimeMillis();
37
38         output.write(("HTTP/1.1 200 OK\n\n<html><body>" +
39                 "木木彬的singleThreadWebServer: " +
40                 time +
41                 "</body></html>").getBytes());
42         output.close();
43         input.close();
44         System.out.println("接收到请求: " + time);
45     }
46
47
48
49     private void openServerSocket() {
50         try {
51             this.serverSocket = new ServerSocket(this.serverPort);
52         } catch (IOException e) {
53             throw new RuntimeException("Cannot open port 8080", e);
54         }
55     }
56
57     public static void main(String[] args) {
58         SingleThreadWebServer singleThreadWebServer = new SingleThreadWebServer(9000);
59         new Thread(singleThreadWebServer).start();
60     }
61 }

  单线程的WebServer,接受connection连接和处理请求都在一个线程中,因此一次只能相应一个请求

实现MultiThreadWebServer

    1、首先开启一个ServerSocket来监听9000端口

    2、一单获得一个连接请求,把它传递给另一个处理线程,这样才能让你的ServerSocket去接受其它的请求

    3、写一个响应。

    实现很简单,把单线程的processClientRequest函数改成WorkThread就好

public class MultiThreadWebServer implements Runnable{
    protected int          serverPort   = 8080;
    protected ServerSocket serverSocket = null;
    protected boolean      isStopped    = false;
    protected Thread       runningThread= null;

    public MultiThreadWebServer(int port){
        this.serverPort = port;
    }

    public void run(){
        synchronized(this){
            this.runningThread = Thread.currentThread();
        }
        openServerSocket();
        while(true){
            Socket clientSocket = null;
            try {
                clientSocket = this.serverSocket.accept();
            } catch (IOException e) {
                e.printStackTrace();
            }
            new Thread(
                    new WorkThread(
                            clientSocket, "mumubin‘s Multithreaded Server")
            ).start();
        }
    }
    private void openServerSocket() {
        try {
            this.serverSocket = new ServerSocket(this.serverPort);
        } catch (IOException e) {
            throw new RuntimeException("Cannot open port 8080", e);
        }
    }
    public static void main(String[] args) {
        MultiThreadWebServer multiThreadWebServer = new MultiThreadWebServer(9090);
        new Thread(multiThreadWebServer).start();
    }

}
public class WorkThread implements Runnable {
    protected Socket clientSocket = null;
    protected String serverText = null;

    public WorkThread(Socket clientSocket, String serverText) {
        this.clientSocket = clientSocket;
        this.serverText = serverText;
    }

    @Override
    public void run() {
        try {
            InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream();
            long time = System.currentTimeMillis();
            outputStream.write(("HTTP/1.1 200 OK\n\nWorkerThread: " +
                    this.serverText + " - " +
                    time +
                    "").getBytes());
            inputStream.close();
            outputStream.flush();
            System.out.println("接收到请求");
            outputStream.close();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

但是呢,之前那些,都没实现HTTP最基本的GET、POST请求,

实现Post、Get方法

  流程如下:

  1、首先开启一个ServerSocket来监听10000端口

  2、一单获得一个连接请求,把它传递给另一个处理线程,这样才能让你的ServerSocket去接受其它的请求

  3、解析请求,看它是GET还是POST,还有传递过来的参数

  4、根据相应的请求写一个响应。

接下来我们先看下Request的具体信息及其实现代码

InputStream inputStream = clientSocket.getInputStream();
InputStream input  = clientSocket.getInputStream();
byte[] byteBuffer = new byte[1000];

do{
    input.read(byteBuffer);
    for (byte a :byteBuffer)
        System.out.print((char)a);
}
while (input.read() != -1);
  GET / HTTP/1.1
  Host: 127.0.0.1:9090
  Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36
  Accept-Encoding: gzip, deflate, sdch
  Accept-Language: zh-CN,zh;q=0.8
  Cookie: _ga=GA1.1.413734972.1430379491

  因此通过解析Request就可以构建doPost和doGet方法,修改后的WorkThread

 1 public class WorkThread implements Runnable {
 2     protected Socket clientSocket = null;
 3     protected String serverText = null;
 4
 5     public WorkThread(Socket clientSocket, String serverText) {
 6         this.clientSocket = clientSocket;
 7         this.serverText = serverText;
 8     }
 9
10     public void doPost()
11     {
12         try {
13             OutputStream outputStream = clientSocket.getOutputStream();
14             outputStream.write(("HTTP/1.1 200 OK\n\nWorkerThread: " +
15                     "this is by post").getBytes());
16             outputStream.flush();
17             outputStream.close();
18         }
19         catch (Exception e)
20         {
21             e.printStackTrace();
22         }
23     }
24
25     public void doGet()
26     {
27         try {
28             OutputStream outputStream = clientSocket.getOutputStream();
29             outputStream.write(("HTTP/1.1 200 OK\n\nWorkerThread: " +
30                     "this is by get").getBytes());
31             outputStream.flush();
32             outputStream.close();
33         }
34         catch (Exception e)
35         {
36             e.printStackTrace();
37         }
38     }
39     @Override
40     public void run() {
41         try {
42             InputStream input  = clientSocket.getInputStream();
43             byte[] byteBuffer = new byte[1000];
44
45                 input.read(byteBuffer);
46                 for (byte a :byteBuffer)
47                     System.out.print((char)a);
48
49             if(byteBuffer[0] == ‘G‘ && byteBuffer[1] == ‘E‘ && byteBuffer[2] == ‘T‘)
50             {
51                 doGet();
52             }
53             else {
54                 doPost();
55             }
56             input.close();
57             System.out.println("接收到请求");
58         }
59         catch (Exception e)
60         {
61             e.printStackTrace();
62         }
63     }
64 }

  基于JDK实现简单的Web服务器

  其实JDK中已经有了对HTTPServer的支持,我们来简单应用下

public class APITest {
    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
        server.createContext("/test", new MyHandler());
        server.setExecutor(null); // creates a default executor
        server.start();
    }

    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "This is the APITest";
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }
}

  

时间: 2024-10-17 06:38:56

Java实现Web Server的相关文章

Salesforce中通过SOAP API和Metadata API开发java的web server服务

1.下载Salesforce平台中WSDL文件 在Salesforce中创建了自己需要用到的对象后,我们想要在别的应用中读写纪录到对象中,首先需要的是自己Salesforce平台的权限通过.登陆自己的Salesforce,下载WSDL文件. 依次点击右上角你的名字中设置-->应用程序设置-->发展-->API. 如果你的是英文,那么依次点击Your Name --> Setup --> App Setup --> Develop --> API. 到了如下页面后,

Tomcat是怎么工作的(2) -- 动手实现山寨版的简单Web Server

本文先讲解一下Java web server都是怎么工作的.web server也叫HTTP server——顾名思义它是用HTTP协议和客户端交互的.客户端一般就是各种各样的浏览器了.相信所有朋友都清楚这个基本事实,否则你也不会看到这个系列文章了. 基于Java的web server必然用到两个极其重要的类:java.net.Socket和java.net.ServerSocket,然后以HTTP消息进行交互. 1. HTTP协议简介(The Hypertext Transfer Protoc

Using OAuth 2.0 for Web Server Applications, verifying a user&#39;s Android in-app subscription

在写本文之前先说些题外话. 前段时间游戏急于在GoolePlay上线,明知道如果不加Auth2.0的校验是不安全的还是暂时略过了这一步,果然没几天就发现后台记录与玩家实际付费不太一致,怀疑有玩家盗刷游戏元宝等,并且真实的走过了GooglePlay的所有支付流程完成道具兑换,时间一长严重性可想而知.经过查阅大量google官方文档后把代码补上,并在这里记录下OAuth 2.0 的使用,Google提供了OAuth2.0的好几种使用用途,每种使用方法都有些不同,具体可以看下这篇博客.在这里只写OAu

[Java聊天室server]实战之二 监听类

前言 学习不论什么一个稍有难度的技术,要对其有充分理性的分析,之后果断做出决定---->也就是人们常说的"多谋善断":本系列尽管涉及的是socket相关的知识,但学习之前,更想和广大程序猿分享的是一种心境:学习是一个循序渐进的过程,心态应该随时调节,保持戒骄戒躁的状态.比方近期在看网易公开课MIT<算法导论>,老师提到,学习算法之前要计算机数学+离散数学+概率论等课程的知识,所以一直学不好算法的程序猿最好还是从基础入手,这都是中国式教育惹的祸啊!(此处省略一万字...

【实例图文详解】OAuth 2.0 for Web Server Applications

原文链接:http://blog.csdn.net/hjun01/article/details/42032841        OAuth 2.0 for Web Server Applications, verifying a user's Android in-app subscription 在写本文之前先说些题外话. 前段时间游戏急于在GoolePlay上线,明知道如果不加Auth2.0的校验是不安全的还是暂时略过了这一步,果然没几天就发现后台记录与玩家实际付费不太一致,怀疑有玩家盗刷

《白帽子讲WEB安全》学习笔记之第15章 web server配置安全

第15章 web server配置安全 15.1 apache安全 在linux部署安装web Server时候一定主要要使用"最小权限原则".尽量不要使用root部署. 15.2 nginx安全 Nginx 安全配置指南技术手册 PDF 下载 免费下载地址在http://linux.linuxidc.com/ 用户名与密码都是www.linuxidc.com 具体下载目录在 /pub/服务器相关教程/Nginx/Nginx 安全配置指南技术手册/ 参考资料:http://my.osc

Java实现web在线预览office文档与pdf文档实例

https://yq.aliyun.com/ziliao/1768?spm=5176.8246799.blogcont.24.1PxYoX 摘要: 本文讲的是Java实现web在线预览office文档与pdf文档实例, 1.首先我们需要找到可以把office转换成pdf的方法,查找资料发现有openoffice这一软件可以把office转换成pdf,这一软件先下载下来,然后记住自己安装的在那个位置.然后在cmd环境下进入安装目录的program目 云计算 云服务器ECS 大数据 建站 备案 文档

Configure mutiple IBM HTTP Server / Other Apache based WEB server on 1 physical server (Section 2)

Continue from the last article...... 2) Confirmed the 80 port of the new added IP is not listened by any other services.   Why need to test this? This is to ensure the 80/443 port of the new created IP is not listened by any other application. Test m

web server(protein protection )搭建过程中遇到的问题

1.StringBuffer中append方法有错误 原因分析:是project默认的JRE系统库和配置的jre不匹配. 解决方法:项目属性->Add Libray->JRE System Library->Alternate JRE(选择Sun JDK 1.6.0_13) 2.文件上传问题 mySmartUpload.setAllowedFilesList("txt");  //设置上传文件类型只能是txt格式 文件上传处理过程 jsp文件: <div id=