最简单的web服务器实现(一)(r4笔记第68天)

tomcat作为web服务器,想必大家做过web开发的都离不开tomcat了,值得庆幸的是tomcat也是开放源代码的,最近准备好好琢磨琢磨tomcat的源码,还没开始就已经感觉到不少的未知恐惧了,慢慢来把。 可能我的学习方式比较急功近利,但是这种方式收效也快,自己记得在<<Java程序员 上班那点事儿>>里作者写过一个最简单的web服务器实现,自己在网上也比较了一下其它的版本,还是感觉那本书里的版本比较好,在此分享出来,因为时间紧,照着书敲了一遍代码,竟然发现里面有一些很细小的错误,自己准备在这个基础上好好改进一把。 首先来看看web服务器的一些基本原理,我们的实验是基于socket的,开放了一个指定的端口,然后会启用对应的线程来处理浏览器中的请求。如果文件不存在,会报出404错误,否则会解析文件的内容。 HttpServer类是后台服务类,会开放对应的端口和socket来处理浏览发出的请求。 HttpThread类是接受浏览器发送请求的类,通过Receive和Answer来接受和处理浏览器发送的请求,然后返回到客户端中。

package new_test;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class HttpServer { 
public static String ROOT="./wwwroot";
public static String defaultPage="index.html";

    public static void main(String[] args) throws IOException{ 
 
            ServerSocket ss = new ServerSocket(8080); 
            while(true){
            Socket s=ss.accept();
                System.out.println("Accept Connection...:");                                   
                 new HttpThread(s).start();
            }        
    } 
}


package new_test;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import
} java.net.Socket;


public class HttpThread extends Thread {


private Socket socket;


public HttpThread(Socket s) {
this.socket = s;


public void run() {
InputStream ins = null;
OutputStream ous = null;
try {
ous = socket.getOutputStream();
ins = socket.getInputStream();
Receive rcv = new Receive(ins);
String sURL = rcv.parse();
System.out.println("sURL is " + sURL);


if (sURL.equals("/")) {
sURL = HttpServer.defaultPage;
}
Answer ans = new Answer(ous);
ans.send(sURL);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (ins != null) {
ins.close();
}
if (ous != null) {
ous.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

package new_test;
import java.io.IOException;
import java.io.InputStream;


public class Receive {
InputStream in = null;


public Receive(InputStream ins) {
this.in = ins;
}


public String parse() {
StringBuffer receiveStr = new StringBuffer(2048);
int i ;
byte[] buffer = new byte[2048];
try {
i = in.read(buffer);
} catch (IOException e) {
i = -1;
}
for (int j = 0; j < i; j++) {
receiveStr.append((char)buffer[j]);


}
return getUri(receiveStr.toString());
}


private String getUri(String receiveStr) {
int index1, index2;
System.out.println("receiveStr is " + receiveStr);
index1 = receiveStr.indexOf(" ");
if (index1 != -1) {
index2 = receiveStr.indexOf(" ", index1 + 1);
if (index2 > index1) {
return receiveStr.substring(index1 + 1, index2);
}
}
return null;
}


}


package new_test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Answer {
OutputStream out = null;

public Answer(OutputStream ous) {
this.out = ous;
}


public void send(String pageFile) {
byte[] bytes = new byte[2048];


FileInputStream fis = null;
try {
File file = new File(HttpServer.ROOT, pageFile);
if (file.exists()) {


fis = new FileInputStream(file);
int ch = fis.read(bytes, 0, 2048);
String sBody = new String(bytes, 0);
String sendMessage = "HTTP/1.1 200 OK\r\n"
+ "Content-Type:text/html\r\n" + "Content-Length:" + ch
+ "\r\n" + "\r\n" + sBody;
out.write(sendMessage.getBytes());
} else {
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>";
out.write(errorMessage.getBytes());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}


}


}

一个简单调用的情况就是,如果不存在对应的页面会直接抛出File Not Found的错误信息

原文发布于微信公众号 - 杨建荣的学习笔记(jianrong-notes)

原文发表时间:2015-03-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Jack的Android之旅

刨解OkHttp之访问连接

因为OkHttp能讲的东西太多了,上一篇文章只是讲到了他的设计架构即责任链模式和异步多线程网络访问,这对于OkHttp只是冰山一角,对于一个网络请求框架,最重要...

1531
来自专栏mathor

Socket

1384
来自专栏Java帮帮-微信公众号-技术文章全总结

Java多线程详解5【面试+工作】

Java多线程详解【面试+工作】 Java线程:新特征-信号量 Java的信号量实际上是一个功能完毕的计数器,对控制一定资源的消费与回收有着很重要的意义,信号量...

42010
来自专栏JavaWeb

基于Spring自定义标签

3674
来自专栏chenssy

【死磕 Spring】----- IOC 之 IOC 初始化总结

前面 13 篇博文从源码层次分析了 IOC 整个初始化过程,这篇就这些内容做一个总结将其连贯起来。

881
来自专栏杂烩

websocket 原

     WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。   

1942
来自专栏chenssy

【死磕 Spring】----- IOC 之 IOC 初始化总结

前面 13 篇博文从源码层次分析了 IOC 整个初始化过程,这篇就这些内容做一个总结将其连贯起来。

1044
来自专栏Flutter知识集

Flutter 实践 MVVM

在做Android或iOS开发时,经常会了解到MVC,MVP和MVVM。MVVM在移动端一度被非常推崇,虽然也有不少反对的声音,不过MVVM确实是不错的设计架构...

3.1K3
来自专栏青青天空树

趣味题:恺撒Caesar密码(c++实现)

描述:Julius Caesar 生活在充满危险和阴谋的年代。为了生存,他首次发明了密码,用于军队的消息传递。假设你是Caesar 军团中的一名军官,需要把Ca...

802
来自专栏Android开发实战

谷歌官方Android应用架构库——LiveData

LiveData 是一个数据持有者类,它持有一个值并允许观察该值。不同于普通的可观察者,LiveData 遵守应用程序组件的生命周期,以便 Observer 可...

1203

扫码关注云+社区

领取腾讯云代金券