在前面我们尝试解释Tomcat的理论,但是呢,很多时候那些复杂的架构和设计会让我们眼花缭乱,以至于忽略了最进本的问题——服务器到底是什么?今天我们就用尽量简单的代码实现一个简易的HTTP服务器。
HTTP启动之后要持续监听,所以我们可以使用NioServer中的Handler就可以了,在修改后的HttpHandler中首先获取到请求报文并打印出报文的头部,包括协议的首行、请求方法的类型、Url和Http版本等,之后将接收到的请求消息(也就是报文信息)封装在一起,最后将这些信息打包成一个报文发送给客户端。
我们这里为了简单,将HttpHandler使用单线程来处理,并且选择SelectionKey的操作类型等都放在Handler中了。
主体代码:
public static void main(String[] args) throws Exception{
//创建ServerSocketChannel,监听8040端口
ServerSocketChannel ssc=ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(8040));
//设置为非阻塞模式
ssc.configureBlocking(false);
//为ssc注册选择器
Selector selector=Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
//创建处理器
while(true){
// 等待请求,每次等待阻塞5s,超过5s后线程继续向下运行
// 这里如果传入0或者不传参数将一直阻塞
if(selector.select(5000)==0){
continue;
}
// 获取待处理的SelectionKey
Iterator<SelectionKey> keyIter=selector.selectedKeys().iterator();
while(keyIter.hasNext()){
SelectionKey key=keyIter.next();
// 启动新线程处理SelectionKey
new Thread(new HttpHandler(key)).run();
// 处理完后,从待处理的SelectionKey迭代器中移除当前所使用的key
keyIter.remove();
}
}
}
我们在上面将端口设置为8040了,因为8080有时候会和其他软件冲突,有时候会被浏览器隐藏,所以我们使用一个更可控的。
之后,我们就来写真正需要干活的Hander:
private static class HttpHandler implements Runnable{
private int bufferSize = 2048;
private String localCharset = "UTF-8";
private SelectionKey key;
public HttpHandler(SelectionKey key){
this.key = key;
}
@Override
public void run() {
try{
// 接收到连接请求时
if(key.isAcceptable()){