当前位置: 首页 > 图文教程 > 网络编程 > JSP > 用Java实现Web服务器

JSP
我认为JSP有问题(上)
我认为JSP有问题(下)
jsp“抓”网页代码的程序
关于在bean里面打印html的利弊看法
bean里面如何打印到html页面
jdbc3中的RowSet 接口规范
Apusic Application Server1.0中jsp源代码泄漏漏洞
Unify的eWave ServletExec拒绝服务漏洞
通过提交超长的GET请求导致IBM HTTP Server远程溢出
在HTTP请求中添加特殊字符导致暴露JSP源代码文件
Resin 1.2 重要源代码暴露漏洞
多中WEB服务器的通用JSp源代码暴露漏洞
Tomcat 暴露JSP文件内容
IBM WebSphere Application Server 暴露JSP文件内容
JRun 2.3.x 范例文件暴露站点安全信息
BEA WebLogic 暴露源代码漏洞
IBM WebSphere Application Server 3.0.2 存在暴露源代码漏洞
Tomcat 3.1 存在暴露网站路径问题
Sun Java Web Server 能让攻击者远程执行任意命令
Netscape 修复 JAVA 安全漏洞

JSP 中的 用Java实现Web服务器


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-03   浏览: 233 ::
收藏到网摘: n/a

HTTP协议简介

 

  超文本传输协议(HTTP)是位于TCP/IP 协议的应用层,是最广为人知的协议,也是互连网中最核心的协议之一,同样,HTTP 也是基于 C/S 或 B/S 模型实现的。事实上,我们使用的浏览器如Netscape 或IE 是实现HTTP 协议中的客户端,而一些常用的Web 服务器软件如Apache、IIS 和iPlanet Web Server 等是实现HTTP 协议中的服务器端。Web 页由服务端资源定位,传输到浏览器,经过浏览器的解释后,被客户所看到。 

  Web 的工作基于客户机/服务器计算模型,由Web 浏览器(客户机)和Web服务器(服务器)构成,两者之间采用超文本传送协议(HTTP)进行通信。HTTP协议是Web浏览器和Web服务器之间的应用层协议,是通用的、无状态的、面向对象的协议。 

  一个完整的HTTP协议会话过程包括四个步骤: 

  ◆ 连接,Web浏览器与Web服务器建立连接,打开一个称为Socket(套接字)的虚拟文件,此文件的建立标志着连接建立成功; 

  ◆ 请求,Web浏览器通过Socket向Web服务器提交请求。HTTP的请求一般是GET或POST命令(POST用于FORM参数的传递); 

  ◆ 应答,Web浏览器提交请求后,通过HTTP协议传送给Web服务器。Web服务器接到后,进行事务处理,处理结果又通过HTTP传回给Web浏览器,从而在Web浏览器上显示出所请求的页面; 

  ◆ 关闭连接,应答结束后Web浏览器与Web服务器必须断开,以保证其它Web浏览器能够与Web服务器建立连接。 
编程思路 

  根据上述HTTP协议的会话过程,本实例中实现了GET请求的Web服务器程序的方法,方法如下: 

  通过创建ServerSocket 类对象,侦听用户指定的端口(为8080),等待并接受客户机请求到端口。创建与Socket相关联的输入流和输出流,然后读取客户机的请求信息。若请求类型是GET,则从请求信息中获取所访问的HTML 文件名;如果HTML 文件存在,则打开HTML 文件,把HTTP 头信息和HTML 文件内容通过Socket 传回给Web浏览器,然后关闭文件,否则发送错误信息给Web 浏览器。最后关闭与相应Web 浏览器连接的Socket。 

  用Java编写Web服务器httpServer.java文件的源代码如下: 

  1. //httpServer.java 
  2. import java.net.*;
  3. import java.io.*;
  4. import java.util.*;
  5. import java.lang.*;
  6. public class httpServer{
  7. public static void main(String args[]) {
  8. int port;
  9. ServerSocket server_socket;
  10. //读取服务器端口号
  11. try {
  12. port = Integer.parseInt(args[0]);
  13. }
  14. catch (Exception e) {
  15. port = 8080;
  16. }
  17. try {
  18. //监听服务器端口,等待连接请求
  19. server_socket = new ServerSocket(port);
  20. System.out.println("httpServer running on port " +
  21. server_socket.getLocalPort());
  22. //显示启动信息
  23. while(true) {
  24. Socket socket = server_socket.accept();
  25. System.out.println("New connection accepted " +
  26. socket.getInetAddress() +
  27. ":" + socket.getPort());
  28. //创建分线程
  29. try {
  30. httpRequestHandler request =
  31. new httpRequestHandler(socket);
  32. Thread thread = new Thread(request);
  33. //启动线程
  34. thread.start();
  35. }
  36. catch(Exception e) {
  37. System.out.println(e);
  38. }
  39. }
  40. }
  41. catch (IOException e) {
  42. System.out.println(e);
  43. }
  44. }
  45. }
  46. class httpRequestHandler implements Runnable
  47. {
  48. final static String CRLF = "\r\n";
  49. Socket socket;
  50. InputStream input;
  51. OutputStream output;
  52. BufferedReader br;
  53. // 构造方法
  54. public httpRequestHandler(Socket socket) throws Exception
  55. {
  56. this.socket = socket;
  57. this.input = socket.getInputStream();
  58. this.output = socket.getOutputStream();
  59. this.br =
  60. new BufferedReader(new InputStreamReader(socket.getInputStream()));
  61. }
  62. // 实现Runnable 接口的run()方法
  63. public void run()
  64. {
  65. try {
  66. processRequest();
  67. }
  68. catch(Exception e) {
  69. System.out.println(e);
  70. }
  71. }
  72. private void processRequest() throws Exception
  73. {
  74. while(true) {
  75. //读取并显示Web 浏览器提交的请求信息
  76. String headerLine = br.readLine();
  77. System.out.println("The client request is "+headerLine);
  78. if(headerLine.equals(CRLF) || headerLine.equals("")) break;
  79. StringTokenizer s = new StringTokenizer(headerLine);
  80. String temp = s.nextToken();
  81. if(temp.equals("GET")) {
  82. String fileName = s.nextToken();
  83. fileName = "." + fileName ;
  84. // 打开所请求的文件
  85. FileInputStream fis = null ;
  86. boolean fileExists = true ;
  87. try
  88. {
  89. fis = new FileInputStream( fileName ) ;
  90. }
  91. catch ( FileNotFoundException e )
  92. {
  93. fileExists = false ;
  94. }
  95. // 完成回应消息
  96. String serverLine = "Server: a simple java httpServer";
  97. String statusLine = null;
  98. String contentTypeLine = null;
  99. String entityBody = null;
  100. String contentLengthLine = "error";
  101. if ( fileExists )
  102. {
  103. statusLine = "HTTP/1.0 200 OK" + CRLF ;
  104. contentTypeLine = "Content-type: " +
  105. contentType( fileName ) + CRLF ;
  106. contentLengthLine = "Content-Length: "
  107. + (new Integer(fis.available())).toString()
  108. + CRLF;
  109. }
  110. else
  111. {
  112. statusLine = "HTTP/1.0 404 Not Found" + CRLF ;
  113. contentTypeLine = "text/html" ;
  114. entityBody = "<HTML>" +
  115. "<HEAD><TITLE>404 Not Found</TITLE></HEAD>" +
  116. "<BODY>404 Not Found"
  117. +"<br>usage:http://yourHostName:port/"
  118. +"fileName.html</BODY></HTML>" ;
  119. }
  120. // 发送到服务器信息
  121. output.write(statusLine.getBytes());
  122. output.write(serverLine.getBytes());
  123. output.write(contentTypeLine.getBytes());
  124. output.write(contentLengthLine.getBytes());
  125. output.write(CRLF.getBytes());
  126. // 发送信息内容
  127. if (fileExists)
  128. {
  129. sendBytes(fis, output) ;
  130. fis.close();
  131. }
  132. else
  133. {
  134. output.write(entityBody.getBytes());
  135. }
  136. }
  137. }
  138. //关闭套接字和流
  139. try {
  140. output.close();
  141. br.close();
  142. socket.close();
  143. }
  144. catch(Exception e) {}
  145. }
  146. private static void sendBytes(FileInputStream fis, OutputStream os)
  147. throws Exception
  148. {
  149. // 创建一个 1K buffer
  150. byte[] buffer = new byte[1024] ;
  151. int bytes = 0 ;
  152. // 将文件输出到套接字输出流中
  153. while ((bytes = fis.read(buffer)) != -1 )
  154. {
  155. os.write(buffer, 0, bytes);
  156. }
  157. }
  158. private static String contentType(String fileName)
  159. {
  160. if (fileName.endsWith(".htm") || fileName.endsWith(".html"))
  161. {
  162. return "text/html";
  163. }
  164. return "fileName";
  165. }
  166. }  


 编程技巧说明

 
  ◆ 主线程设计 

  主线程的设计就是在主线程httpServer 类中实现了服务器端口的侦听,服务器接受一个客户端请求之后创建一个线程实例处理请求,代码如下: 

  1. import java.net.*;
  2. import java.io.*;
  3. import java.util.*;
  4. import java.lang.*;
  5. public class httpServer{
  6. public static void main(String args[]) {
  7. port;
  8. ServerSocket server_socket;
  9. //读取服务器端口号
  10. try {
  11. port = Integer.parseInt(args[0]);
  12. }
  13. catch (Exception e) {
  14. port = 8080;
  15. }
  16. try {
  17. //监听服务器端口,等待连接请求
  18. server_socket = new ServerSocket(port);
  19. System.out.println("httpServer running on port " 
  20. +server_socket.getLocalPort());
  21. ..........
  22. .......... 


  ◆ 连接处理分线程设计 

  在分线程httpRequestHandler 类中实现了HTTP 协议的处理,这个类实现了Runnable 接口,代码如下: 

  1. class httpRequestHandler implements Runnable
  2. {
  3. final static String CRLF = "\r\n";
  4. Socket socket;
  5. InputStream input;
  6. OutputStream output;
  7. BufferedReader br;
  8. // 构造方法
  9. public httpRequestHandler(Socket socket) throws Exception
  10. {
  11. this.socket = socket;
  12. //得到输入输出流
  13. this.input = socket.getInputStream();
  14. this.output = socket.getOutputStream();
  15. this.br =
  16. new BufferedReader(new InputStreamReader(socket.getInputStream()));
  17. }
  18. // 实现Runnable 接口的run()方法
  19. public void run()
  20. {
  21. try {
  22. processRequest();
  23. }
  24. catch(Exception e) {
  25. System.out.println(e);
  26. }


  ◆ 构建processRequest()方法来处理信息的接收和发送 

  作为实现Runnable 接口的主要内容,在run()方法中调用processRequest()方法来处理客户请求内容的接收和服务器返回信息的发送,代码如下: 

  1. private void processRequest() throws Exception
  2. {
  3. while(true) {
  4. //读取并显示Web 浏览器提交的请求信息
  5. String headerLine = br.readLine();
  6. System.out.println("The client request is "+ headerLine);
  7. if(headerLine.equals(CRLF) || headerLine.equals("")) break;
  8. //根据请求字符串中的空格拆分客户请求
  9. StringTokenizer s = new StringTokenizer(headerLine);
  10. String temp = s.nextToken();
  11. if(temp.equals("GET")) {
  12. String fileName = s.nextToken();
  13. fileName = "." + fileName ;
  14. .............
  15. ............. 


  在processRequest()方法中得到客户端请求后,利用一个StringTokenizer 类完成了字符串的拆分,这个类可以实现根据字符串中指定的分隔符(缺省为空格)将字符串拆分成为字串的功能。利用nextToken()方法依次得到这些字串;sendBytes()方法完成信息内容的发送,contentType()方法用于判断文件的类型。 

  显示Web页面 

  显示 Web 页面的index.html 文件代码如下: 

<html>
<head>
<meta http-equiv="Content-Language" content="zh-cn">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Java Web 服务器</title>
</head>
<body>
<p>********* <font color="#FF0000">欢迎你的到来!</font>*********</p>
<p>这是一个用 Java 语言实现的 Web 服务器</p>
<hr>
</body>
</html> 

运行实例



  为了测试上述程序的正确性,将编译后的httpServer.class、httpRequestHandler.class和上面的index.html文件置于网络的某台主机的同一目录中。 

  首先运行服务器程序 java httpServer 8080,服务器程序运行后显示端口信息“httpServer runing on port 8080”, 然后在浏览器的地址栏中输入http://localhost:8080/index.html,就可以正确显示网页,同时在显示“httpServer runing on port 8080 ”窗口中服务器会出现一些信息。