使用Java实现Web服务器编程

以下是个人学习过程中的一点记录

在进行实验完成一个简单的web服务器之前,我们要对HTTP协议报文有一个更深的了解,以下即为请求报文



在平常使用web服务器时,我们关心请求方法(一般是GET/POST),URL,以及如果是POST方法我们还关心请求包体中的数据,因此我们需要对报文进行分解处理。

下面可以简单分析一下我们具体要执行的步骤


创建ServerSocket对象,利用serverSocket对象中的accept()函数等待请求的到达,之后处理完成后重新进行等待。

创建Request对象,主要进行分词提取出我们需要的方法,URL,以及报文。

创建Response对象,主要根据request后得到的请求方法采取不同的处理方式并输出。

执行时,获取inputstream和outputstream,分别提供给Request和Response对象。



1. 首先是web服务器类

构造ServerSocket函数,将其绑定为本机的8080端口

然后进入while循环,accept()函数等待,没有时就进行阻塞

然后将输入流输出流分别交给请求和响应函数

执行完毕后,关闭ServerSocket,让其重新进入while循环


2. request类

首先创建4个变量,输入流,url,方法,数据包体


然后在构造函数中,根据 方法,url,版本之间的空格进行spilit,然后一次进行赋值


最后创建get方法即可获取值


3.response类

首先创建输出流和请求类变量,然后根据构造函数进行赋值


然后根据方法的不同,进行不同的处理

首先建立一个HashMap,存取参数


当方法为POST时,spilit拿出数据体,并存入公共域


然后模拟控制器,执行必要功能(此处为叠加计算值)


最后将结果加入一段html段中一起显示


注意要加入响应头,否则无法解析,会报错并且不会显示

当方法为GET时,根据参数的提交方式,对url进行解析,取出参数并存入公共域



4.测试用前端根据个人要求修改,适当修改后台的模拟处理即可运行。


以下贴上完整代码


public class WebServer {

    /**

     *@param args

     */

    public static void main(String[] args) {

       // TODOAuto-generated method stub


       ServerSocketserverSocket = null;

       try {

           // 使用本机

           serverSocket = newServerSocket(8080, 1, InetAddress.getByName("localhost"));

       }catch (IOException e) {

           e.printStackTrace();

       }

       while (true) {

           try {

              // 等待连接

              Socketsocket = serverSocket.accept();

              InputStreaminput = socket.getInputStream();

              OutputStreamoutput = socket.getOutputStream();

              // request解析出url

              Requestrequest = new Request(input);

              // response输出

              Responseresponse = new Response(output, request);

              response.response();

              socket.close();

           }catch (Exception e) {

              e.printStackTrace();

              continue;

           }

       }

    }

}


public class Request {


    // GET格式,类似也存在POST

    // GET /test.html HTTP/1.1

    // Host:localhost:8080

    // Connection: keep-alive

    // Upgrade-Insecure-Requests: 1

    // User-Agent:Mozilla/5.0 (Windows NT 10.0;WOW64) AppleWebKit/537.36 (KHTML,

    // likeGecko)Chrome/74.0.3729.169Safari/537.36

    // Accept:

    // text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3

    // Accept-Encoding:gzip,deflate,br

    // Accept-Language:zh-CN,zh;q=0.9,en;q=0.8


    private InputStream input = null;

    private String url = null;

    private StringBuffer body = new StringBuffer(4096);

    private String method = null;


    public Request(InputStream input) {

       this.input = input;

       try {

           // 下面分解url,首先读取内容到body中

           byte[] buffer = new byte[4096];

           int len = input.read(buffer);

           for (int i = 0; i < len; i++)

              body.append((char) buffer[i]);



           // 拿到报文要获取url,根据注释中的格式进行分析

           url = body.toString().split(" ")[1];

           method = body.toString().split(" ")[0];

       }catch (IOException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }

    }


    public String getUrl() {

       return url;

    }


    public String getBody() {

       return body.toString();

    }


    public String getMethod() {

       return method;

    }

}


public class Response {


    private OutputStream output;

    private Request request;

    HashMapmemory = new HashMap();


    public Response(OutputStream output, Request request) {

       this.output = output;

       this.request = request;

    }


    public void response() {


       byte[] bytes = new byte[4096];

       FileInputStreamfilestream = null;

       try {


           if (request.getMethod().equals("POST")) {


              // 拿出数据体,以KV对存储

              Stringbody = request.getBody();

              String[]bodys = body.split("\r|\n");

              String[]parms = bodys[bodys.length - 1].split("&|=");

              for (int i = 1; i < parms.length - 1; i += 2) {

                  memory.put(parms[i - 1], parms[i]);

              }


              // 此处模拟控制器

              int result = 0;

              result+= Integer.parseInt(memory.get("t1")) + Integer.parseInt(memory.get("t2"))

                     + Integer.parseInt(memory.get("t3")) + Integer.parseInt(memory.get("t4"))

                     + Integer.parseInt(memory.get("t5")) + Integer.parseInt(memory.get("t6"))

                     + Integer.parseInt(memory.get("t7")) + Integer.parseInt(memory.get("t8"))

                     + Integer.parseInt(memory.get("t9")) + Integer.parseInt(memory.get("t10"))

                     + Integer.parseInt(memory.get("t11")) + Integer.parseInt(memory.get("t12"))

                     + Integer.parseInt(memory.get("t13")) + Integer.parseInt(memory.get("t14"))

                     + Integer.parseInt(memory.get("t15"));


              Stringbuf = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML

4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n"

                     +"<html>\r\n" + "<head>\r\n"

                     +"<meta

http-equiv=\"Content-Type\" content=\"text/html;

charset=UTF-8\">\r\n"

                     +"<title>Insert title

here</title>\r\n" + "</head>\r\n" + "<body>\r\n" + "\r\n" + " 你的测试得分为"

                     +result + "</body>" + "</html>";

              StringresponseHead = "HTTP/1.1 200 ok\r\nContent-Type:

text/html\r\nContent-Length: " + buf.length()

                     +"\r\n\r\n";

              output.write(responseHead.getBytes());

              output.write(buf.getBytes());


           }else {

              String[]parms = request.getUrl().split("\\?")[1].split("&|=");

              for (int i = 0; i < parms.length - 1; i += 2) {

                  memory.put(parms[i], parms[i + 1]);

              }


              // 模拟控制器

              Filefile = new File("./src" + request.getUrl().split("\\?")[0]);

              if (file.exists()) {

                  filestream = new FileInputStream(file);

                  // 加入头

                  StringresponseHead = "HTTP/1.1 200 ok\r\nContent-Type:

text/html\r\nContent-Length: "

                         +file.length() + "\r\n\r\n";

                  output.write(responseHead.getBytes());

                  output.write((memory.get("name") + "你好").getBytes());

                  int len = 0;

                  while ((len = filestream.read(bytes, 0, 4096)) != -1) {

                     output.write(bytes, 0, len);

                  }

              }else {

                  StringerrorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n"

                         +"Content-Length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>";

                  output.write(errorMessage.getBytes());

              }

           }

       }catch (Exception e) {

       }finally {

           try {

              if (filestream != null)

                  filestream.close();

           }catch (IOException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

           }

       }

    }

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339

推荐阅读更多精彩内容