java实现web服务器
参考:http://jingyan.baidu.com/article/48206aeafba520216ad6b3e0.html
完整项目代码:http://yunpan.cn/QiJTQAhyIbzKd (提取码:4f0e)
首先上代码:
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个最基本的技术:1、java多线程技术,比较简单;2、socket编程技术。
1、java多线程技术:每次当浏览器请求该服务器发送数据的时候,服务器都为这个请求新建一个线程(new Thread()),所有的线程独立工作,因此一个web server能同时接受多个client的请求。(详细的多线程技术参见其他文章)
2、socket技术:socket分为ServerSocket和一般的Socket。web服务器中,必须要有一个ServerSocket对象,在新建ServerSocket对象时,要为其指定一个监听端口:
new ServerSocket(5000);
然后用一个无穷循环来循环检测该端口有没有请求:
while(true) {
client=server.accept(); //接受客户机的连接请求
new ConnectionThread(client,client_id).start(); //为该client创建服务线程
client_id++;//客户端标识加1
}
当该端口接收到请求的时候,ServerSocket对象便接受该请求,并为该请求创建一个socket对象,该socket对象便可以与客户端的socket对象之间交换数据,数据交换是基于TCP协议的。
流程图:
至于其他的数据流操作,可以参考其他资料,数据java基本操作。
完整的项目运行方案:
1、在Eclipse里新建java项目,添加一个类web_server.class,将上面的代码复制进去,保存。
2、用记事本写两个HTML文件index.html和error.html,保存。
3、要运行该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文件,所以访问失败: