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:如有不對請指出~~~~
相關文章
- NIO學習二、NIO的基本使用
- NIO學習一、NIO簡介
- NIO(三)基礎
- Java NIO學習系列三:SelectorJava
- Java NIO 學習Java
- Nio再學習之NIO的buffer緩衝區
- java BIO、NIO學習Java
- Java NIO學習系列四:NIO和IO對比Java
- NIO相關基礎篇三
- 深入學習Netty(一)NIO基礎篇Netty
- java BIO/NIO/AIO 學習JavaAI
- 【死磕NIO】— NIO基礎詳解
- NIO基礎
- Java NIO學習系列二:ChannelJava
- Java NIO學習系列一:BufferJava
- nio再學習之通道channel
- [網路]NIO學習筆記筆記
- Asyncdb(三):Java NIOJava
- 偶的伺服器:nio,困惑!伺服器
- Java 多執行緒NIO學習Java執行緒
- Java NIO 核心元件學習筆記Java元件筆記
- 【NIO】Java NIO之通道Java
- java基礎-java NIOJava
- Java NIO學習系列七:Path、Files、AsynchronousFileChannelJava
- Java NIO學習系列五:I/O模型Java模型
- Java NIO 緩衝區學習筆記Java筆記
- 【NIO】Java NIO之緩衝Java
- Java NIO系列2:NIO概述Java
- NIO 伺服器搭建筆記伺服器筆記
- 【NIO】Java NIO之選擇器Java
- Java IO學習筆記五:BIO到NIOJava筆記
- Java網路程式設計和NIO詳解9:基於NIO的網路程式設計框架NettyJava程式設計框架Netty
- Java NIOJava
- NIO模型模型
- JavaEE進階知識學習----Java NIO-4Java
- NIO相關基礎篇一
- NIO相關基礎篇二
- 網路程式設計NIO:BIO和NIO程式設計