手写一个Web服务器,极简版Tomcat
网络传输是通过遵守HTTP协议的数据格式来传输的。
HTTP协议是由标准化组织W3C(World Wide Web Consortium,万维网联盟)和IETF(Internet Engineering Task Force,国际互联网工程任务组)推动和制定的,最后形成RFC文档 [RFC1945](HTTP/1.0)和RFC2616[HTTP/1.1]
可以响应HTTP请求的程序就是Web Server,实现方法并没有统一规范,可以说HTTP协议就是Web Server和网络传输数据之间的接口规范。以后我们会看到,Web Server和处理程序之间的规范是CGI。
一些常见的Web Server有Apache、Nginx、Microsoft IIS、Google GWS。
我们这里手写一个Web Server。
首先我们需要接收网络的请求,根据OSI七层模型,网络的实现是分层的。Web Server属于应用层,要调用下一层(传输层,TCP/IP)的接口,来得到对方发来的网络请求,这个接口就叫做Socket。《计算机网络:自顶向下方法》中写到:“Socket是同一台主机内应用层与传输层之间的接口。因为Socket是建立网络应用程序的可编程接口,所以Socket也被称为应用程序和网络之间的API”。
一、最简单的Web Server
要编写一个Web Server,我们调用系统Socket接口,监听8180端口上收到的网络数据,打印到控制台,并给出一个符合http标准的响应,代码如下:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
public class Server {
public static void main(String[] args) {
Server server = new Server();
server.start();
}
public void start() {
try {
ServerSocket serverSocket = new ServerSocket(8180); // 调用系统socket接口,监听某端口的socket请求
Socket httpInputSocket = serverSocket.accept(); // 在这里,程序线程等待socket输入
this.printHttpRequest(httpInputSocket);
this.responseHttpRequest(httpInputSocket);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 打印来自外部的http请求
*
* @param httpInputSocket
*/
private void printHttpRequest(Socket httpInputSocket) {
try {
// 调用系统IO,打印请求
BufferedReader br = new BufferedReader(new InputStreamReader(httpInputSocket.getInputStream()));
StringBuilder receivedHttp = new StringBuilder();
String line = null;
while ( !"".equals(line = br.readLine())) {
receivedHttp.append(line);
receivedHttp.append(System.getProperty("line.searator", "\n"));
}
System.out.println(receivedHttp.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 返回页面供请求方显示
*
* @param httpInputSocket
*/
private void responseHttpRequest(Socket httpInputSocket) {
// 创建响应体
StringBuilder contextText = new StringBuilder();
contextText.append(
"<html>" +
"<head>" +
"<title>Build A Web Server</title>" +
"</head>" +
"<body>Hello World, This is my page</body>" +
"</html>");
// 创建响应头
StringBuilder headText = new StringBuilder();
headText.append("HTTP/1.1").append(" ").append("200").append(" ").append("OK").append("\n");
headText.append("Server:myServer").append(" ").append("0.0.1v").append(" ");
headText.append("Date:Sat,"+" ").append(new Date()).append("\n");
headText.append("Content-Type:text/html;charset=UTF-8").append("\n");
headText.append("Content-Length:").append(contextText.toString().getBytes().length).append("\n");
// http response
StringBuilder responseText = new StringBuilder();
responseText.append(headText).append("\n").append(contextText);
System.out.println(responseText);
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new OutputStreamWriter(httpInputSocket.getOutputStream()));
bw.write(responseText.toString());
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
至此,一个100行不到的Web Server就写好了,运行一下,在浏览器里访问:http://localhost:8180/,可以看到结果:
程序控制台也正确打印:
这个Web Server会对请求到8180端口的所有请求都返回同样的页面,比如我们访问http://localhost:8180/really?foo=123,结果也是一样的:
从这个例子可以看出,通过HTTP请求进行访问,可以不用创建socket客户端。
注意printHttpRequest和responseHttpRequest都要调用才能显示效果,就是说先执行socket 输入流的读取,然后再执行socket输出流输出
手写一个Web服务器,极简版Tomcat的更多相关文章
- Tomcat源码分析 (一)----- 手写一个web服务器
作为后端开发人员,在实际的工作中我们会非常高频地使用到web服务器.而tomcat作为web服务器领域中举足轻重的一个web框架,又是不能不学习和了解的. tomcat其实是一个web框架,那么其内部 ...
- 用C写一个web服务器(二) I/O多路复用之epoll
.container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .conta ...
- 使用node.js 文档里的方法写一个web服务器
刚刚看了node.js文档里的一个小例子,就是用 node.js 写一个web服务器的小例子 上代码 (*^▽^*) //helloworld.js// 使用node.js写一个服务器 const h ...
- 使用Node.js原生API写一个web服务器
Node.js是JavaScript基础上发展起来的语言,所以前端开发者应该天生就会一点.一般我们会用它来做CLI工具或者Web服务器,做Web服务器也有很多成熟的框架,比如Express和Koa.但 ...
- wsgiref手写一个web服务端
''' 通过wsgiref写一个web服务端先讲讲wsgiref吧,基于网络通信其根本就是基于socket,所以wsgiref同样也是通过对socket进行封装,避免写过多的代码,将一系列的操作封装成 ...
- 用java写一个web服务器
一.超文本传输协议 Web服务器和浏览器通过HTTP协议在Internet上发送和接收消息.HTTP协议是一种请求-应答式的协议——客户端发送一个请求,服务器返回该请求的应答.HTTP协议使用可靠的T ...
- 【教程】手写简易web服务器
package com.littlepage.testjdbc; import java.io.BufferedReader; import java.io.FileReader; import ja ...
- 手写简易WEB服务器
今天我们来写一个类似于Tomcat的简易服务器.可供大家深入理解一下tomcat的工作原理,本文仅供新手参考,请各位大神指正!首先我们要准备的知识是: Socket编程 HTML HTTP协议 服务器 ...
- 用C写一个web服务器(一) 基础功能
.container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .conta ...
随机推荐
- 【CodeForces】835F Roads in the Kingdom
一.题目 题目描述 王国有\(n\)座城市与\(n\)条有长度的街道,保证所有城市直接或间接联通,我们定义王国的直径为所有点对最短距离中的最大值,现因财政危机需拆除一条道路并同时要求所有城市仍然联通, ...
- zookeeper 集群搭建 转
通过 VMware ,我们安装了三台虚拟机,用来搭建 zookeeper 集群,虚拟机网络地址如下: hostname ipaddress ...
- beego和gin对比
一.对mvc的支持 beego支持完整的mvc M:Model,beego orm,把数据库数据变成object 特性 支持go的所有类型存储 更简洁的curd风格 完整实现了健壮的ORM 支持的数据 ...
- Helium文档8-WebUI自动化-wait_until等待元素出现
前言 wait_until等待某个条件为真才继续往下执行.默认的超时时间为10s,每0.5查询一次,这俩参数选填.可以设置超时时间和轮询间隔. 可以作为添加后校验元素是否存在的场景 入参介绍 def ...
- MySQL备份和恢复[2]-基于LVM的快照备份
准备工作 请求锁定所有表 mysql> FLUSH TABLES WITH READ LOCK; 记录二进制日志文件及事件位置 mysql> FLUSH LOGS; mysql> S ...
- MySQL数据库基础-3
SQL语言 结构化的查询云烟 有国际标准. 非常容易学习的,关注数据本身,类似于shell SQL解释器 命令行效率比较高 应用编程接口 ODBC:Open Database Connectivity ...
- JS时间扩展插件
前言 原生JS有些没定义的方法只能自己封装了,比如获取现在相隔本年过了几天以及过了多少周,这些都是原JS里没有的方法,现在插件只有一些方法,后期再慢慢扩展 插件使用方法 引用TimeToPack.js ...
- pv操作是否会造成死锁呢?
看了一些pv操作的例子,有一些基本原理不是想得很清楚. 有一个进程 while(true) { p(s); ...... v(s); } s的初值为1. 那么我的问题是,当多个该进程需要执行时,是否会 ...
- git学习(八) git stash操作
git stash命令的作用就是将目前还不想提交的但是已经修改的内容进行保存至堆栈中,后续可以在某个分支上恢复出堆栈中的内容.git stash作用的范围包括工作区和暂存区中的内容,没有提交的内容都会 ...
- 4. Validator校验器的五大核心组件,一个都不能少
困难是弹簧,你弱它就强.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众号[BAT的 ...