介紹如何基於java語言實現一個簡單的Http伺服器
介紹三個方面的內容:
1)Http協議的基本知識;
2)java.net.Socket類;
3)java.net.ServerSocket類。
讀完後你可以把這個伺服器用多執行緒的技術重新編寫一個更好的伺服器。
由於Web伺服器使用Http協議通訊的因此也把它叫做Http伺服器,Http使用可靠的TCP連線來工作,它是面向連線的通訊方式,這意味著客戶端和伺服器每次通訊都建立自己的連線,它又是無狀態的連線,當資料傳輸完畢後客戶端和伺服器端的連線立刻關閉,這樣可以節省伺服器的資源,當然如果需要傳輸大量的資料,你可以在Request的頭設定Connection=keep-alive使得可以複用這一個連線通道。在
一個Http請求包括三個重要的部分:
Method-URI-Protocol/Version
Request headers
Entity body
下面是一個Http請求的例子:
POST /servlet/default.jsp HTTP/1.1
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: localhost
Referer: http://localhost/ch8/SendDetails.htm
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
LastName=Franks&FirstName=Michael
其中第一行是Method-URI-Protocol/Version ,這是非常重要的部分,你需要從中讀取客戶端資料傳輸的方式,
HTTP響應和請求非常相似,同樣包括三個部分:
Protocol-Status code-Description
Response headers
Entity body
下面是一個具體的例子:
HTTP/1.1 200 OK
Server: Microsoft-IIS/4.0
Date: Mon, 3 Jan 1998 13:13:33 GMT
Content-Type: text/html
Last-Modified: Mon, 11 Jan 1998 13:23:42 GMT
Content-Length: 112
something in html style......................
通常在J2ME聯網中我們需要判斷響應的狀態碼來決定下一步的操作,比如200代表連線成功。現在你應該清楚為什麼這麼做了吧。同樣在Header和Entity body中有一個CRLF分割。
現在我們來看看java中的Socket類,socket其實是對程式語言的一種抽象,它提供了在網路上端對端訪問的可能,但是它並不依賴於程式語言,你完全可以使用java和c語言通過socket來進行通訊,在java中是通過java.net.Socket來實現的,當你要構建一個socket的時候,你只是需要呼叫它的構造器 public Socket(String host,int port),其中host代表目標主機的地址或名字,port代表埠,比如80。當我們建立了一個Socket的例項後我們就可以進行通訊了,如果你要基於位元組來通訊,那麼你可以通過呼叫getOutputStream()和getInputStream()來得到OutputStream和InputStream的物件,如果你是基於字元通訊的話那麼你可以用PrintWriter和BufferedReader進行二次包裝,例如PrintWriter pw = new PrintWriter(socket.getOutputStream(),true)。下面是簡單的使用socket通訊的程式碼片斷,實現了向127.0.0.1:8080傳送Http請求的功能
1 ocketsocket=newSocket("127.0.0.1","8080"); 2 OutputStreamos=socket.getOutputStream(); 3 booleanautoflush=true; 4 PrintWriterout=newPrintWriter(socket.getOutputStream(),autoflush); 5 BufferedReaderin=newBufferedReader(newInputStreamReader(socket.getInputStream())); 6 7 //sendanHTTPrequesttothewebserver 8 out.println("GET/index.jspHTTP/1.1"); 9 out.println("Host:localhost:8080"); 10 out.println("Connection:Close"); 11 out.println(); 12 13 //readtheresponse 14 booleanloop=true; 15 StringBuffersb=newStringBuffer(8096); 16 17 while(loop){ 18 if(in.ready()){ 19 inti=0; 20 while(i!=-1){ 21 i=in.read(); 22 sb.append((char)i); 23 } 24 loop=false; 25 } 26 Thread.currentThread().sleep(50); 27 } 28 29 //displaytheresponsetotheoutconsole 30 System.out.println(sb.toString()); 31 socket.close();
接下來介紹與Socket類對應的ServerSocket類的使用,與Socket代表客戶端不同的是,ServerSocket是代表伺服器端的,因為它必須在某個埠不停的監視是否有客戶端連線進來。通過呼叫ServerSocket的構造器我們可以建立起監聽特定埠的Server。
例如,new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1")); 這樣我們在本機的8080埠建立起來了ServerSocket。當你呼叫ServerSocket的accept()方法後,只有有連線進來的時候,這個方法才會返回一個Socket的物件,這樣你就可以使用這個例項來接受或者傳送資料了。記住當我們傳輸資料結束後要記得呼叫clos()方法來釋放資源。