NIO学习三、基于NIO的WEB服务器
本文主要是对于NIO的应用,没什么特别的地方。
一、准备过程
实现的http服务器只可以访问静态资源,需要将文件放在webroot目录下。
二、设计流程:
1、开发Request进行请求资源的解析,找到请求的路径,如果请求不合法抛出异常。
2、开发Response将资源返回给客户端
3、开发HttpServer,创建ServerSocketChannel,获得客户端的SocketChannel进行处理。并将产生异常的请求关闭。
三、具体代码:
HttpServer:
package com.webserver;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
public class HttpServer {
protected static final String WEB_ROOT=System.getProperty("user.dir")+ File.separator+"webroot";
protected static final int PORT=8080;
protected static final String HOST="127.0.0.1";
private ServerSocketChannel serverSocketChannel;
private Selector selector;
public static void main(String args[]){
HttpServer httpServer=new HttpServer();
httpServer.run();
}
public void run() {
//开始运行先创建服务器
if (serverSocketChannel==null) {
System.out.println("服务器启动。。。。");
createServer();
}
//一直等待创建连接
while(true) {
try {
this.selector.select();//这地方会阻塞等待创建连接
Set<SelectionKey> sets=this.selector.selectedKeys();
Iterator<SelectionKey> iterator=sets.iterator();
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
while(iterator.hasNext()){
SelectionKey selectionKey=iterator.next();
//处理感兴趣的事件
dohandelInteresting(selectionKey);
iterator.remove();
}
} catch (Exception e) {
System.out.println(e.getMessage());
continue;
}
}
}
private void dohandelInteresting(SelectionKey selectionKey)throws Exception{
if (selectionKey.isAcceptable()){//如果有连接接入那么进行处理
doHandleLink();//处理连接
}else if (selectionKey.isReadable()) {//希望请求数据
SocketChannel socketChannel= (SocketChannel) selectionKey.channel();
try {
//处理请求,处理请求的时候可能会发生的异常:请求出错或者
//远程客户端关闭连接,但服务端还进行操作,这时候统统关闭服务端连接
doHandleAccess(socketChannel);
} catch (Exception e) {
//如果处理请求的过程中发生异常就由服务端取消注册并且关闭它
socketChannel.close();
selectionKey.cancel();
throw e;
}
}
}
private void doHandleLink() throws IOException {
SocketChannel socketChannel=this.serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
}
//处理请求分为两步,(1)解析请求资源,(2)回送给客户端
private void doHandleAccess(SocketChannel socketChannel) throws Exception {
//解析请求
Request request = doHandleRequest(socketChannel);
//回送客户端
doHandleReply(request, socketChannel);
}
private void doHandleReply(Request request, SocketChannel socketChannel) throws Exception {
Response response=new Response(socketChannel,request);
response.sendStaticResource();
}
//处理到来的request请求
private Request doHandleRequest(SocketChannel socketChannel) throws Exception {
Request request=new Request(socketChannel);
request.doHandelRequestContext();
return request;
}
//创建服务端
private void createServer() {
try {
this.serverSocketChannel=ServerSocketChannel.open();
this.serverSocketChannel.socket().bind(new InetSocketAddress(HOST,PORT));
this.serverSocketChannel.configureBlocking(false);
createSelector();
this.serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
}
private void createSelector() throws IOException {
this.selector=Selector.open();
}
}
Request:
package com.webserver;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
//接受请求,找出对应的url
public class Request {
private String requestContext;
private SocketChannel socketChannel;
private String url;
public Request(SocketChannel socketChannel){
this.socketChannel=socketChannel;
}
public String getRequestContext() {
return requestContext;
}
public String getUrl() {
return url;
}
void doHandelRequestContext() throws Exception{
paserRequestContext();
paserRequestUrl();
}
private void paserRequestContext() throws Exception {
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
byteBuffer.clear();
byte[]temp=new byte[1024];
int length=0;
StringBuilder stringBuilder=new StringBuilder();
while ((length = socketChannel.read(byteBuffer)) > 0) {
stringBuilder.append(new String(byteBuffer.array(), 0, length));
}
this.requestContext = stringBuilder.toString();
if (this.requestContext.trim().equals("")) {
throw new Exception("请求不合法");
}
}
private void paserRequestUrl(){
int index=requestContext.indexOf(" ");
if (index!=-1){
url=requestContext.substring(index+1,requestContext.indexOf(" ",index+1));
}
//默认请求/index.html
if(url.equals("/")){
url="/index.html";
}
}
}
Response
package com.webserver;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
public class Response {
private SocketChannel socketChannel;
private Request request;
public Response(SocketChannel socketChannel){
this(socketChannel,null);
}
public Response(SocketChannel socketChannel,Request request){
this.request=request;
this.socketChannel=socketChannel;
}
public void setRequest(Request request) {
this.request = request;
}
public void sendStaticResource() throws Exception {
FileInputStream fileInputStream=null;
File file =null;
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
try {
file= new File(HttpServer.WEB_ROOT, request.getUrl());
if (file.exists()) {
fileInputStream = new FileInputStream(file);
FileChannel fileChannel=fileInputStream.getChannel();
byteBuffer.put(("HTTP/1.1 200\r\n"
+ "Content-Type: text/html\r\n"
+ "Content-Length: "
+ file.length()
+ "\r\n"
+ "\r\n").getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
byteBuffer.clear();
fileChannel.transferTo(0,fileChannel.size(),socketChannel);
} 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>";
byteBuffer.put(errorMessage.getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
byteBuffer.clear();
throw new Exception("没找到指定文件");
}
}catch (Exception e){
System.out.println(e.getMessage());
}
finally {
if(null!=fileInputStream){
fileInputStream.close();
}
}
}
}
四、访问
ps:如有不对请指出~~~~