Java實現簡單的站點請求模式
阿新 • • 發佈:2018-12-13
Java實現簡單的站點請求模式
概述
本次實現的是瀏覽器(客戶端)訪問特定站點ip和埠,自定義socket來監聽該請求,解析請求內容以及做出響應。
以下是在com.yzz.tomcat下的三個類
- HttpServer:socket監聽ip,接收客戶端請求。
- HttpRequest:解析客戶端HTTP請求。
- HttpResponse:對客戶端請求做出響應。
HttpServer
await()方法這裡麵包括了socket的建立,連線的監聽,對HTTP請求的解析以及對請求做出響應。
package com.yzz.tomcat.server;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import com.yzz.tomcat.request.HttpRequest;
import com.yzz.tomcat.response.HttpResponse;
public class HttpServer {
//獲取專案中的檔案
public static final String WEEB_ROOT = System.getProperty("user.dir")+File.separator+"webroot";
//關閉監聽字元
public static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
//是否監聽關閉
private boolean shutdown = false;
/**
* 這裡是對特定ip埠進行監聽
* 監聽8080埠
* ip是本地ip
*/
public void await(){
ServerSocket serverSocket = null ;
int port = 8080;
try{
serverSocket = new ServerSocket(port,100,InetAddress.getByName("127.0.0.1"));
}catch (Exception e) {
e.printStackTrace();
System.out.println("serverSocket獲取失敗");
}
while(!shutdown){
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
//The method blocks until a connection is made.
socket = serverSocket.accept();
//設定讀取超時時間
socket.setSoTimeout(3000);
//獲取出入輸出流
input = socket.getInputStream();
output = socket.getOutputStream();
//建立HttpRequest物件,呼叫parse()方法來解析HTTP請求
HttpRequest request = new HttpRequest(input);
request.parse();
//新建HttpResponse物件,對請求進行對應的處理
HttpResponse response = new HttpResponse(output);
response.setHttpRequest(request);
//向客戶端傳送靜態的資源
response.sendStaticResource();
//在做出響應後,關閉socket連線
socket.close();
//判斷是否是客戶端發來的關閉監聽指令
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
}
HttpRequest
這裡需要特別注意的是,在讀取HTTP請求內容的時候與普通的檔案流有所區別,詳情見註釋
package com.yzz.tomcat.request;
import java.io.InputStream;
public class HttpRequest {
//socket連線的輸入流
private InputStream inputStream;
//統一欄位識別符號
private String uri;
//HTTP請求內容
private StringBuffer request;
public HttpRequest(InputStream inputStream) {
this.inputStream = inputStream;
}
/**
* 解析HTTP請求
* 這裡只是對HTTP協議的第一行的URI做了解析,其他內容這裡並沒有做關注
* 注意:socket的輸入流的檔案流有區別,檔案流可以迴圈讀取,直到出現某一個標誌位,結束
* 但是socket的輸入流不滿足這種情況,當讀取完成之後,流會處於等待狀態,並沒有結束,因為是端對端的傳輸,不知道
* 客戶端時候是傳輸完畢了,所以會處於無限期的等待狀態中。
* 解決:目前的解決辦法是一次性讀完所有的HTTP請求資源,這裡是2048byte
*/
public void parse() {
request = new StringBuffer();
try {
if (null == inputStream)
return;
byte buf[] = new byte[2048];
int len = 0;
len = inputStream.read(buf);
if(len != -1)
request.append(new String(buf,0,len));
System.out.println(request.toString());
parseUri();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解析URI
*/
private void parseUri() {
int index1;
int index2;
index1 = request.indexOf(" ");
index2 = request.indexOf(" ", index1 + 1);
if (index2 > index1)
uri = request.substring(index1 + 1, index2);
System.out.println("uri:"+uri);
}
public String getUri() {
return uri;
}
}
HttpResponse
響應做的比較簡單,請求的資源存在就將資源通過輸出流返回給客戶端,否則返回404頁面
package com.yzz.tomcat.response;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import com.yzz.tomcat.request.HttpRequest;
import com.yzz.tomcat.server.HttpServer;
public class HttpResponse {
//socket連線輸出流
private OutputStream out;
//HTTP請求物件
private HttpRequest httpRequest;
//緩衝byte陣列長度
public static final int BUFFER_SIZE = 1024;
//404 URI
public static final String PAGE_404 = "/404.html";
public HttpResponse(OutputStream out) {
this.out = out;
}
public void setHttpRequest(HttpRequest httpRequest) {
this.httpRequest = httpRequest;
}
/**
* 向客戶端響應靜態資源
*/
public void sendStaticResource() {
File file = new File(HttpServer.WEEB_ROOT, httpRequest.getUri());
FileInputStream fis = null;
if(!file.exists()){
file = new File(HttpServer.WEEB_ROOT+PAGE_404);
}
try {
fis = new FileInputStream(file);
byte[] buf = new byte[BUFFER_SIZE];
int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(null != fis){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
演示
工程結構
其中靜態資源存放在tomcat的webroot目錄下
結果
1.正常請求
2.錯誤請求
3.結束監聽
總結
本次只是簡單的對socket進行了利用,對於響應還沒有加上HTTP規範,下片我們繼續來優化。