一个简单的Java web服务器实现
前言
一个简单的Java web服务器实现,比较简单,基于java.net.Socket和java.net.ServerSocket实现;
程序执行步骤
- 创建一个ServerSocket对象;
- 调用ServerSocket对象的accept方法,等待连接,连接成功会返回一个Socket对象,否则一直阻塞等待;
- 从Socket对象中获取InputStream和OutputStream字节流,这两个流分别对应request请求和response响应;
- 处理请求:读取InputStream字节流信息,转成字符串形式,并解析,这里的解析比较简单,仅仅获取uri(统一资源标识符)信息;
- 处理响应:根据解析出来的uri信息,从WEB_ROOT目录中寻找请求的资源资源文件, 读取资源文件,并将其写入到OutputStream字节流中;
- 关闭Socket对象;
- 转到步骤2,继续等待连接请求;
代码实现
服务器实现:
package ex01.pyrmont; import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.File; public class HttpServer { /**
* WEB_ROOT是HTML和其它文件存放的目录. 这里的WEB_ROOT为工作目录下的webroot目录
*/
public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot"; // 关闭服务命令
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; public static void main(String[] args) {
HttpServer server = new HttpServer();
//等待连接请求
server.await();
} public void await() {
ServerSocket serverSocket = null;
int port = 8080;
try {
//服务器套接字对象
serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
} // 循环等待一个请求
while (true) {
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
//等待连接,连接成功后,返回一个Socket对象
socket = serverSocket.accept();
input = socket.getInputStream();
output = socket.getOutputStream(); // 创建Request对象并解析
Request request = new Request(input);
request.parse();
// 检查是否是关闭服务命令
if (request.getUri().equals(SHUTDOWN_COMMAND)) {
break;
} // 创建 Response 对象
Response response = new Response(output);
response.setRequest(request);
response.sendStaticResource(); // 关闭 socket 对象
socket.close(); } catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
}
Request类:
package ex01.pyrmont; import java.io.InputStream;
import java.io.IOException; public class Request { private InputStream input;
private String uri; public Request(InputStream input) {
this.input = input;
} //从InputStream中读取request信息,并从request中获取uri值
public void parse() {
StringBuffer request = new StringBuffer(2048);
int i;
byte[] buffer = new byte[2048];
try {
i = input.read(buffer);
} catch (IOException e) {
e.printStackTrace();
i = -1;
}
for (int j = 0; j < i; j++) {
request.append((char) buffer[j]);
}
System.out.print(request.toString());
uri = parseUri(request.toString());
} /**
*
* requestString形式如下:
* GET /index.html HTTP/1.1
* Host: localhost:8080
* Connection: keep-alive
* Cache-Control: max-age=0
* ...
* 该函数目的就是为了获取/index.html字符串
*/
private String parseUri(String requestString) {
int index1, index2;
index1 = requestString.indexOf(' ');
if (index1 != -1) {
index2 = requestString.indexOf(' ', index1 + 1);
if (index2 > index1)
return requestString.substring(index1 + 1, index2);
}
return null;
} public String getUri() {
return uri;
} }
Response类:
package ex01.pyrmont; import java.io.OutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File; /*
HTTP Response = Status-Line
*(( general-header | response-header | entity-header ) CRLF)
CRLF
[ message-body ]
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
*/ public class Response { private static final int BUFFER_SIZE = 1024;
Request request;
OutputStream output; public Response(OutputStream output) {
this.output = output;
} public void setRequest(Request request) {
this.request = request;
} public void sendStaticResource() throws IOException {
byte[] bytes = new byte[BUFFER_SIZE];
FileInputStream fis = null;
try {
//将web文件写入到OutputStream字节流中
File file = new File(HttpServer.WEB_ROOT, request.getUri());
if (file.exists()) {
fis = new FileInputStream(file);
int ch = fis.read(bytes, 0, BUFFER_SIZE);
while (ch != -1) {
output.write(bytes, 0, ch);
ch = fis.read(bytes, 0, BUFFER_SIZE);
}
} else {
// file not found
String errorMessage = "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) {
// thrown if cannot instantiate a File object
System.out.println(e.toString());
} finally {
if (fis != null)
fis.close();
}
}
}
结果测试
访问存在的资源文件(注意存放在工程目录的webroot文件夹里):
访问不存在的资源文件:
关闭服务器:
参考资料
《深入剖析Tomcat》
一个简单的Java web服务器实现的更多相关文章
- Golang学习-第二篇 搭建一个简单的Go Web服务器
序言 由于本人一直从事Web服务器端的程序开发,所以在学习Golang也想从Web这里开始学起,如果对Golang还不太清楚怎么搭建环境的朋友们可以参考我的上一篇文章 Golang的简单介绍及Wind ...
- 使用eclipse创建一个简单的Java Web应用程序
关于Java JDK/JRE.Tomcat的配置等等都没什么好说的,主要记录一下使用Eclipse创建web工程时的一些点以及说一说自己用IDEA的创建失败的过程(IDEA没运行成功...暂时不想弄了 ...
- nodeJS搭建一个简单的(代理)web服务器
前端获取数据时经常遇见跨域问题,以前一直用nginx做反向代理.最近在用vuejs,发现webpack-dev-server的代理简单好用.于是仿照写了一个简单的web服务器,用于非webpack的项 ...
- 一个简单的Java Web项目搭建流程
今天试图在服务器上搭建一个web服务器,顺便回顾了java web项目的入门,使用Servlet处理HTTP请求,并记录日志等操作.当很久没有做过web项目时,有些东西还是很容易忘记的. Maven配 ...
- 简单的Java Web服务器
import java.io.FileInputStream; import java.io.OutputStream; import java.net.ServerSocket; import ja ...
- 一个简单的java web项目 仅实现添加
连接数据库已经进行判断 要求: 1登录账号:要求由6到12位字母.数字.下划线组成,只有字母可以开头:(1分) 2登录密码:要求显示“• ”或“*”表示输入位数,密码要求八位以上字母.数字组成.(1分 ...
- 常用/常见Java Web 服务器/应用服务器Logo图文介绍
常用/常见应用服务器介绍:自己总结.整理一些常见的应用服务器,资料主要来源于网上. 常用Java Web 服务器Java Web应用程序需要部署在Java web服务器中运行,常用的Java ...
- AngularJs与Java Web服务器交互
AngularJs是Google工程师研发的产品,它的强大之处不是几句话就能描述的,只有真正使用过的人才能体会到,笔者准备在这篇文章中,以一个简单的登录校验的例子说明如何使用AngularJs和Web ...
- JSP学习笔记(三):简单的Tomcat Web服务器
注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...
随机推荐
- HoverTree开发日志之验证码
HoverTree是一个ASP.NET的开源CMS,目前包含文章系统,图库和留言板功能.代码完全开放,文章内容页生成了静态的HTM页面,留言板提供留言审核功能,文章可以发布HTML源代码,图片上传同时 ...
- C#[抽象类,接口]
Ⅰ.抽象类 1.抽象类.抽象方法 抽象类:通常情况下,它里面有抽象方法,类前面定义了一个abstract 抽象方法:只定义了方法的名称,没有定义方法的内容 2.为什么要使用抽象类.抽象方法? 都是为了 ...
- c#重点[封装,继承,多肽]
面向对象的语言三大特点:封装.继承.多态 Ⅰ.封装:是把类的内部隐藏起来,以防止外部世界看见的一个面向对象的概念,通过关键字去控制变量,方法的访问权限. 1).访问修饰符: Ⅱ.继承: eg:我们建一 ...
- 背水一战 Windows 10 (3) - UI: 窗口全屏, 窗口尺寸
[源码下载] 背水一战 Windows 10 (3) - UI: 窗口全屏, 窗口尺寸 作者:webabcd 介绍背水一战 Windows 10 之 UI 窗口全屏 窗口尺寸 示例1.窗口全屏UI/F ...
- DatagramSocket收发UDP数据包
Java的Socket通信分为TCP和UDP两种,Socket和ServerSocket类用于TCP通信,DatagramSocket用于UDP通信. 使用DatagramSocket发送UDP数据包 ...
- Java---Java的面试题(一)
1.什么是Java虚拟机?为什么Java被称作是"平台无关的编程语言"? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节 ...
- ListView 使用 LiveBindings 显示超过 200 条记录
ListView 使用 LiveBindings 预设加载 200 条记录,这也许是速度的考量,但当需要全部加载的的情况时,该如何做呢?只需加入下面二行代码即可: FDQuery1.OptionsIn ...
- MongoDB学习-安装流程
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的. 支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型. ...
- 关于【error C3646: 未知重写说明符】的若干种可能性
如果在程序中出现了error C3646,那么这个错误可能是由多种问题所导致的,这篇文章将对多种错误及对应解决方法进行分析. 在MSDN的官方网站中,Complier Error C3646的定义为u ...
- Global和Globals
$a= '1234'; $a = 'abc'; $GLOBAS['b']='123'; function showVar(){ echo $a;//什么也输不出来 echo $b;//123(全局变量 ...