java實現web服務器html
參考:http://jingyan.baidu.com/article/48206aeafba520216ad6b3e0.htmljava
完整項目代碼:http://yunpan.cn/QiJTQAhyIbzKd (提取碼:4f0e)web
首先上代碼:編程
1 /**
2 * @author hewenwu 3 * 功能:模擬web服務程序 4 * 原理:java多線程、socket編程,TCP協議 5 */
6
7 import java.io.*; 8 import java.net.*; 9
10 public class web_server{ 11
12 public static void main(String args[]) { 13
14 int client_id = 1; //初始化客戶端id爲1,client_id惟一標識一個socket和與其對應的一個java線程
15
16 int PORT = 5000; //該服務程序監聽的端口
17
18 ServerSocket server=null; //服務端的serversocket
19
20 Socket client=null; //客戶端socket
21
22 try{ 23 server=new ServerSocket(PORT); //實例化serverclient對象,監聽5000端口。一個web服務器只須要一個serversocket
24
25 System.out.println("Web Server is listening on port:"+server.getLocalPort()); 26
27 /*這裏用到了一個無窮循環,讓serversocket始終報紙監聽,隨時接受客戶端程序的請求*/
28 while(true) { 29
30 client=server.accept(); //接受客戶機的鏈接請求
31
32 new ConnectionThread(client,client_id).start(); //爲該client建立服務線程
33
34 client_id++;//客戶端標識加1
35 } 36
37 }catch(Exception e) { 38
39 System.out.println(e); 40 } 41 } 42 } 43
44
45
46 /* 繼承子Thread類,ConnnectionThread類完成與一個Web瀏覽器的通訊 */
47
48 class ConnectionThread extends Thread { 49
50 public Socket client = null; // 鏈接Web瀏覽器的socket字
51
52 public int counter = 0; // 計數器
53
54 public ConnectionThread(Socket cl , int c) { 55
56 client=cl; 57 counter=c; 58 } 59
60 @SuppressWarnings("deprecation") 61
62 public void run() 63 { 64 try{ 65
66 String destIP=client.getInetAddress().toString(); // 客戶機IP地址
67
68 int destport=client.getPort(); // 客戶機端口號
69
70 System.out.println("Connection "+counter+":connected to "+destIP+" on port "+destport+"."); 71
72 PrintStream outstream=new PrintStream(client.getOutputStream());//獲取與客戶機的打印輸出流
73
74 DataInputStream instream=new DataInputStream(client.getInputStream());//獲取從客戶機的數據輸入流
75
76 String inline=instream.readLine(); // 讀取Web瀏覽器提交的請求信息
77
78 System.out.println("Received:"+inline); 79
80 if (get_request_type(inline)) { // 若是是GET請求
81
82 String filename=get_file_name(inline); 83
84 File file=new File(filename); 85
86 if (file.exists()) { // 若文件存在,則將文件送給Web瀏覽器
87
88 System.out.println(filename+" requested."); 89
90 //發送HTML的head信息
91
92 outstream.println("HTTP/1.0 200 OK"); 93
94 outstream.println("MIME_version:1.0"); 95
96 outstream.println("Content_Type:text/html"); 97
98 int len=(int)file.length(); 99
100 outstream.println("Content_Length:"+len); 101
102 outstream.println(""); 103
104 //發送HTML正文信息
105 sendfile(outstream,file); // 發送文件 106
107 //清空輸出流
108 outstream.flush(); 109
110 } else { // 文件不存在時
111
112 String filenam="error.html"; 113
114 //獲得錯誤信息頁面
115 File file1=new File(filenam); 116
117 System.out.println(filename+" requested."); 118
119 //輸出HTML的頭信息
120 outstream.println("HTTP/1.0 200 OK"); 121
122 outstream.println("MIME_version:1.0"); 123
124 outstream.println("Content_Type:text/html"); 125
126 int len=(int)file.length(); 127
128 outstream.println("Content_Length:"+len); 129
130 outstream.println(""); 131
132 //輸出錯誤信息文件
133 sendfile(outstream,file1); // 發送文件 134
135 //清空緩衝區
136 outstream.flush(); 137 } 138 } 139
140 //設置延時,等待文件傳送完畢
141 long m1=1; 142 while (m1<11100000) 143 { 144 m1++; 145
146 } 147
148 //關閉客戶端socket
149 client.close(); 150
151 }catch(IOException e) { 152
153 System.out.println("Exception:"+e); 154 } 155 } 156
157
158 /* 獲取請求類型是否爲「GET」 */
159
160 boolean get_request_type(String s) { 161
162 if (s.length()>0) 163
164 { 165 if(s.substring(0,3).equalsIgnoreCase("GET")) 166
167 return true; 168 } 169
170 return false; 171 } 172
173 /* 獲取要訪問的文件名 */
174
175 String get_file_name(String s) { 176
177 /*get請求的第一行信息格式爲:「GET /books/?name=Professional%20Ajax HTTP/1.1」 178 String.substring(int i)方法是從第i個字符開始取,取出後面全部的字符 179 String.substring(int begin,int end)方法是取出從begin到end的全部字符 180 */
181
182 String file_name = s.substring(s.indexOf(' ')+1);//這一條是把get後面全部的字符串取出來
183
184 file_name = file_name.substring(0,file_name.indexOf(' ')); 185
186 try{ 187
188 if(file_name.charAt(0)=='/') 189
190 file_name=file_name.substring(1); 191
192 }catch(StringIndexOutOfBoundsException e) { 193
194 System.out.println("Exception:"+e); 195 } 196
197 if (file_name.equals("")) { 198
199 file_name="index.html"; 200 } 201
202 return file_name; 203 } 204
205 /*把指定文件發送給Web瀏覽器 */
206
207 void sendfile(PrintStream outs,File file){ 208
209 try{ 210
211 DataInputStream in=new DataInputStream(new FileInputStream(file)); 212
213 int len=(int)file.length(); 214
215 byte buf[]=new byte[len]; 216
217 in.readFully(buf); 218
219 outs.write(buf,0,len); 220
221 outs.flush(); 222
223 in.close(); 224
225 }catch(Exception e){ 226
227 System.out.println("Error retrieving file."); 228
229 System.exit(1); 230
231 } 232 } 233 }
web_server原理解析:瀏覽器
該程序用到的2個最基本的技術:一、java多線程技術,比較簡單;二、socket編程技術。服務器
一、java多線程技術:每次當瀏覽器請求該服務器發送數據的時候,服務器都爲這個請求新建一個線程(new Thread()),全部的線程獨立工做,所以一個web server能同時接受多個client的請求。(詳細的多線程技術參見其餘文章)多線程
二、socket技術:socket分爲ServerSocket和通常的Socket。web服務器中,必需要有一個ServerSocket對象,在新建ServerSocket對象時,要爲其指定一個監聽端口:socket
new ServerSocket(5000);spa
而後用一個無窮循環來循環檢測該端口有沒有請求:.net
while(true) {
client=server.accept(); //接受客戶機的鏈接請求
new ConnectionThread(client,client_id).start(); //爲該client建立服務線程
client_id++;//客戶端標識加1
}
當該端口接收到請求的時候,ServerSocket對象便接受該請求,併爲該請求建立一個socket對象,該socket對象即可以與客戶端的socket對象之間交換數據,數據交換是基於TCP協議的。
流程圖:
至於其餘的數據流操做,能夠參考其餘資料,數據java基本操做。
完整的項目運行方案:
一、在Eclipse裏新建java項目,添加一個類web_server.class,將上面的代碼複製進去,保存。
二、用記事本寫兩個HTML文件index.html和error.html,保存。
三、要運行該web server有2種方法:用Eclipse或者用dos命令:
用Eclipse:用Eclipse須要將index.html和error.html文件放入到項目文件夾與src同級的文件夾下,而且刷新Eclipse裏面的項目:
運行該項目,便可。
用dos命令:首先用javac命令編譯web_server.java文件,獲得web_server.class和ConnectionThread.class文件,將web_server.class、ConnectionThread.class、index.html和error.html文件放入同一個文件夾,而後用java web_server運行改程序便可。
瀏覽器訪問:在地址欄輸入:
http://localhost:5000/index.html,回車,能夠看到訪問成功:
輸入:http://localhost:5000/index1.html,回車,因爲沒有index1.html文件,因此訪問失敗: