JAVA简易WEB服务器(一)

简介:

这一篇博客开始将和大家一起使用JAVA编写一个简易的Web服务器。
众所周知Web服务器与客户端之间的通信是使用HTTP协议的。HTTP是一个客户端和服务器端请求和应答的标准(TCP)。因为HTTP协议是基于TCP协议的,所以我将使用JAVA中的Socket完成这个简易的Web服务器。关于HTTP更详细的资料,各位可以查阅相关资料进行了解。
在服务器编写之前,我们还是先来看一下浏览器与服务器之间通信的规则到底如何。
首先,我们是用ServerSocket来模拟一个服务端,通过浏览器访问,查看浏览器请求的内容:

import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

import org.junit.Test;

/**
 * HTTP协议测试
 * 
 * @author jianggujin
 * 
 */
public class HQHttpProtocolTest
{
   @Test
   public void server() throws Exception
   {
      ServerSocket serverSocket = new ServerSocket(80);
      Socket socket = serverSocket.accept();
      InputStream stream = socket.getInputStream();
      int r = -1;
      while ((r = stream.read()) != -1)
      {
         System.out.print((char) r);
      }
   }
}

使用junit运行,并通过浏览器访问:http://127.0.0.1,我们可以看到控制台上输出浏览器的请求内容如下:

GET / HTTP/1.1
Host: 127.0.0.1
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 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8

为了更好的分析请求内容,我们编写一个HTML页面提交一些数据,再次查看请求内容:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>
<body>
<form method="post" action="http://127.0.0.1?test=123">
<input type="text" name="name"/>
<input type="submit"/>
</form>
</body>
</html>

在输入框中输入bob,点击按钮提交,观察控制台输出:

POST /?test=123 HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Content-Length: 8
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8

name=bob

我们来分析一下这段请求内容:
第一行:由三部分组成,中间以空格分开,第一部分为请求方法(GET、POST),第二部分为请求路径以及查询参数,第三部分为HTTP协议版本(HTTP/1.1)
第二行到第十行:请求的头信息,请求头名称与值之间通过:分隔
第十一行:空行
第十二行:提交的表单内容
综上,我们可以得到如下结论:请求信息第一行为请求方法、请求路径以及查询参数、HTTP协议版本,通过\r\n换行后紧跟着请求头信息,各头信息之间通过\r\n换行,请求头信息结束后跟着一个空行,空行之后紧跟着一行为请求数据,需要注意的是,这里面只模拟了最简单的表单提交,至于复杂的文件提交等,这里面不讨论,请求内容格式略有不同
至此,客户端请求的内容我们已经知道了,下面我们再来看看服务端在接收到请求后响应数据的格式,我们新建一个Web项目用于测试,编辑Html页面内容如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>
<body>this is test page.
</body>
</html>

启动服务器,然后编写客户端测试代码,获得服务端返回数据:

import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

import org.junit.Test;

/**
 * HTTP协议测试
 * 
 * @author jianggujin
 * 
 */
public class HQHttpProtocolTest
{

   public void server() throws Exception
   {
      ServerSocket serverSocket = new ServerSocket(80);
      Socket socket = serverSocket.accept();
      InputStream stream = socket.getInputStream();
      // BufferedInputStream inputStream = new BufferedInputStream(stream);
      int r = -1;
      while ((r = stream.read()) != -1)
      {
         System.out.print((char) r);
      }
   }

   @Test
   public void client() throws Exception
   {
      Socket socket = new Socket("127.0.0.1", 80);
      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
            socket.getOutputStream()));
      writer.write("GET /Servlet/test.html HTTP/1.1\r\n");
      writer.write("Host: 127.0.0.1\r\n");
      writer.write("Connection: keep-alive\r\n");
      writer.write("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n");
      writer.write("User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36\r\n");
      writer.write("Accept-Encoding: gzip,deflate,sdch\r\n");
      writer.write("Accept-Language: zh-CN,zh;q=0.8\r\n");
      writer.write("\r\n");
      writer.flush();
      InputStream stream = socket.getInputStream();
      int r = -1;
      while ((r = stream.read()) != -1)
      {
         System.out.print((char) r);
      }
   }
}

运行程序获得服务器返回内容如下:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"129-1456125361109"
Last-Modified: Mon, 22 Feb 2016 07:16:01 GMT
Content-Type: text/html
Content-Length: 129
Date: Mon, 22 Feb 2016 08:08:32 GMT

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>
<body>this is test page.
</body>
</html>

同样的,我们来分析一下这段返回消息:
第一行由三部分组成,中间以空格分开,第一部分为HTTP协议版本(HTTP/1.1),第二部分为响应状态码,第三部分为响应状态描述
第二行到第七行为响应头信息,响应头名称与值之间通过:分隔
第八行:空行
第九行到结束:响应内容
综上,我们可以得到如下结论:请求信息第一行为HTTP协议版本、响应状态码、响应状态描述,通过\r\n换行后紧跟着响应头信息,各头信息之间通过\r\n换行,响应头信息结束后跟着一个空行,空行之后紧跟着响应数据,需要注意的是,除这种响应外,其实还有其他的相应方式,比如chunk,此处不讨论,可查阅相关资料

到现在为止,我们已经分析完了客户端的请求内容格式以及服务端相应内容的格式,这一篇就到此为止了,接下来的博客中,我们将一步一步的进行服务器端的编写。

目录
相关文章
|
8天前
|
数据采集 Java 数据挖掘
Java IO异常处理:在Web爬虫开发中的实践
Java IO异常处理:在Web爬虫开发中的实践
|
6天前
|
关系型数据库 Java MySQL
"解锁Java Web传奇之旅:从JDK1.8到Tomcat,再到MariaDB,一场跨越数据库的冒险安装盛宴,挑战你的技术极限!"
【9月更文挑战第6天】在Linux环境下安装JDK 1.8、Tomcat和MariaDB是搭建Java Web应用的关键步骤。本文详细介绍了使用apt-get安装OpenJDK 1.8、下载并配置Tomcat,以及安装和安全设置MariaDB(MySQL的开源分支)的方法。通过这些步骤,您可以快速构建一个稳定、高效的开发和部署环境,并验证各组件是否正确安装和运行。这为您的Java Web应用提供了一个坚实的基础。
17 0
|
11天前
|
API C# 开发框架
WPF与Web服务集成大揭秘:手把手教你调用RESTful API,客户端与服务器端优劣对比全解析!
【8月更文挑战第31天】在现代软件开发中,WPF 和 Web 服务各具特色。WPF 以其出色的界面展示能力受到欢迎,而 Web 服务则凭借跨平台和易维护性在互联网应用中占有一席之地。本文探讨了 WPF 如何通过 HttpClient 类调用 RESTful API,并展示了基于 ASP.NET Core 的 Web 服务如何实现同样的功能。通过对比分析,揭示了两者各自的优缺点:WPF 客户端直接处理数据,减轻服务器负担,但需处理网络异常;Web 服务则能利用服务器端功能如缓存和权限验证,但可能增加服务器负载。希望本文能帮助开发者根据具体需求选择合适的技术方案。
41 0
|
11天前
|
Rust 安全 开发者
惊爆!Xamarin 携手机器学习,开启智能应用新纪元,个性化体验与跨平台优势完美融合大揭秘!
【8月更文挑战第31天】随着互联网的发展,Web应用对性能和安全性要求不断提高。Rust凭借卓越的性能、内存安全及丰富生态,成为构建高性能Web服务器的理想选择。本文通过一个简单示例,展示如何使用Rust和Actix-web框架搭建基本Web服务器,从创建项目到运行服务器全程指导,帮助读者领略Rust在Web后端开发中的强大能力。通过实践,读者可以体验到Rust在性能和安全性方面的优势,以及其在Web开发领域的巨大潜力。
22 0
|
11天前
|
Java Maven Android开发
解锁Web开发新技能:从零开始的Struts 2之旅——让你的Java编程之路更加宽广,首个应用实例带你飞!
【8月更文挑战第31天】对于初学者,掌握 Struts 2 框架不仅能提升 Web 开发能力,还能深入了解 MVC 架构。Struts 2 是一个基于 Servlet 的 Java 框架,提供表单验证、文件上传、国际化等功能,便于快速构建易维护的 Web 应用。本文通过示例演示如何从零开始搭建环境并创建一个简单的 Struts 2 项目,包括配置 `struts.xml`、编写 Action 类及视图文件,并配置 web.xml。通过这些步骤,你将学会基本的开发流程,为进一步学习高级功能打下基础。
23 0
|
11天前
|
前端开发 Java UED
JSF遇上Material Design:一场视觉革命,如何让传统Java Web应用焕发新生?
【8月更文挑战第31天】在当前的Web开发领域,用户体验和界面美观性至关重要。Google推出的Material Design凭借其独特的动画、鲜艳的颜色和简洁的布局广受好评。将其应用于JavaServer Faces(JSF)项目,能显著提升应用的现代感和用户交互体验。本文介绍如何通过PrimeFaces等组件库在JSF应用中实现Material Design风格,包括添加依赖、使用组件及响应式布局等步骤,为用户提供美观且功能丰富的界面。
19 0
|
11天前
|
Java 数据库 API
JSF与JPA的史诗级联盟:如何编织数据持久化的华丽织锦,重塑Web应用的荣耀
【8月更文挑战第31天】JavaServer Faces (JSF) 和 Java Persistence API (JPA) 分别是构建Java Web应用的用户界面组件框架和持久化标准。结合使用JSF与JPA,能够打造强大的数据驱动Web应用。首先,通过定义实体类(如`User`)和配置`persistence.xml`来设置JPA环境。然后,在JSF中利用Managed Bean(如`UserBean`)管理业务逻辑,通过`EntityManager`执行数据持久化操作。
21 0
|
11天前
|
Java 前端开发 Apache
Apache Wicket与Spring MVC等Java Web框架大PK,究竟谁才是你的最佳拍档?点击揭秘!
【8月更文挑战第31天】在Java Web开发领域,众多框架各具特色。Apache Wicket以组件化开发和易用性脱颖而出,提高了代码的可维护性和可读性。相比之下,Spring MVC拥有强大的生态系统,但学习曲线较陡;JSF与Java EE紧密集成,但在性能和灵活性上略逊一筹;Struts2虽成熟,但在RESTful API支持上不足。选择框架时还需考虑社区支持和文档完善程度。希望本文能帮助开发者找到最适合自己的框架。
23 0
|
11天前
|
Java Spring 开发者
Java Web开发新潮流:Vaadin与Spring Boot强强联手,打造高效便捷的应用体验!
【8月更文挑战第31天】《Vaadin与Spring Boot集成:最佳实践指南》介绍了如何结合Vaadin和Spring Boot的优势进行高效Java Web开发。文章首先概述了集成的基本步骤,包括引入依赖和配置自动功能,然后通过示例展示了如何创建和使用Vaadin组件。相较于传统框架,这种集成方式简化了配置、提升了开发效率并便于部署。尽管可能存在性能和学习曲线方面的挑战,但合理的框架组合能显著提升应用开发的质量和速度。
23 0
|
11天前
|
开发者 Java Spring
【绝技揭秘】掌握Vaadin数据绑定:一键同步Java对象,告别手动数据烦恼,轻松玩转Web应用开发!
【8月更文挑战第31天】Vaadin不仅是一个功能丰富的Java Web应用框架,还提供了强大的数据绑定机制,使开发者能轻松连接UI组件与后端Java对象,简化Web应用开发流程。本文通过创建一个简单的用户信息表单示例,详细介绍了如何使用Vaadin的`Binder`类实现数据绑定,包括字段与模型属性的双向绑定及数据验证。通过这个示例,开发者可以更专注于业务逻辑而非繁琐的数据同步工作,提高开发效率和应用可维护性。
31 0