这个程序改写自O'reilly的Java网路程序设计书中的jhttp.java程序,我将启动的接口作了一些改变,并服务客户端的线程部份独立出来,使这个程序的服务类更具一般性,不受限制于服务器接口的管理方式。
这个程序可以判别客户端请求的资源类型,并传回适当的标头,因为这是一个最简单的HTTP服务器,它不处理客户端的标头,并只接受基本的GET方法。
基本上这个程序一点都不难,线程与Socket的使用都很基本,只要您稍微懂得HTTP协定,都可以看得懂这个程序,有兴趣的可以参照HTTP协定继续完成功能更丰富的HTTP服务器。
以下为程序码内容:
package onlyfun.caterpillar;
import java.io.*; import java.net.*; import java.util.Date;
class HttpClient implements Runnable { private Socket clientSkt; private File docRoot; private String defaultFile;;
public HttpClient(Socket s, String root, String indexFile) { clientSkt = s; docRoot = new File(root); defaultFile = indexFile; }
// 根据要求的档名判断传回类型 public String returnContentType(String fileName) { if(fileName.endsWith(".html") || fileName.endsWith(".htm")) return "text/html"; // HTML网页 else if(fileName.endsWith(".txt") || fileName.endsWith(".java")) return "text/plain"; // 文字类型 else if(fileName.endsWith(".gif")) return "image/gif"; // GIF图档 else if(fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) return "image/jpeg"; // JPEG图档 else if(fileName.endsWith(".class")) return "application/octec-stream"; // 二进位应用?{式文件 else // 其它不可判别的文件一律视为文字档类型 return "text/plain"; }
public void run() { String request; // 要求的方法 String contentType; // 文件类型 String httpVersion = ""; // HTTP协定版本 File requestedFile; // 要求的文件
try { PrintStream printStream = new PrintStream( clientSkt.getOutputStream()); BufferedReader clientReader = new BufferedReader( new InputStreamReader(clientSkt.getInputStream()));
String get = clientReader.readLine(); // 分离Request的内容 String[] tokens = get.split("[ \t]"); request = tokens[0];
if(request.equals("GET")) { String file = tokens[1];
if(file.endsWith("/")) // GET / file += defaultFile; contentType = returnContentType(file);
if(tokens.length >= 3) { httpVersion = tokens[2]; }
// 我们不处理客户端的标头 while((get = clientReader.readLine()) != null) { if(get.trim().equals("")) break; }
try { requestedFile = new File( docRoot, file.substring(1, file.length())); FileInputStream fileInputStream = new FileInputStream(requestedFile);
// 读入请求的文件 int fileLength = (int)requestedFile.length(); byte[] requestedData = new byte[fileLength]; fileInputStream.read(requestedData); fileInputStream.close();
// 写出标头至客户端 if(httpVersion.startsWith("HTTP/")) { printStream.print("HTTP/1.0 200 OK\r\n"); Date now = new Date(); printStream.print("Date: " + now + "\r\n"); printStream.print("Server: TinyHttpd v0.1\r\n"); printStream.print( "Content-length: " + fileLength + "\r\n"); printStream.print( "Content-type: " + contentType + "\r\n\r\n"); }
// 将文件传给客户端 printStream.write(requestedData); printStream.close(); } catch(IOException e) { // 找不到文件 if(httpVersion.startsWith("HTTP/")) { printStream.print("HTTP/1.0 404 File Not Found\r\n"); Date now = new Date(); printStream.print("Date: " + now + "\r\n"); printStream.print("Server: TinyHttpd v0.1\r\n"); printStream.print("Content-type: text/html\r\n\r\n"); } }
// 显示错误讯息网页 printStream.println( "<HTML><HEAD><TITLE>File Not Found</TITLE></HEAD>" + "<BODY><H1>HTTP Error 404: File Not Found" + "</H1></BODY></HTML>"); printStream.close(); } else { // 客户端请求了一个没有实现的方法,例如POST等 if(httpVersion.startsWith("HTTP/")) { printStream.print("HTTP/1.0 501 Not Implemented\r\n"); Date now = new Date(); printStream.print("Date: " + now + "\r\n"); printStream.print("Server: TinyHttpd v1.0\r\n"); printStream.print("Content-type: text/html\r\n\r\n"); } } printStream.println( "<HTML><HEAD><TITLE>Not Implemented</TITLE></HEAD>" + "<BODY><H1>HTTP Error 501: Not Implemented" + "</H1></BODY></HTML>"); printStream.close(); } catch(IOException e) { e.printStackTrace(); }
try { clientSkt.close(); } catch(IOException e) { e.printStackTrace(); } } }
package onlyfun.caterpillar;
import java.io.*; import java.net.*;
public class SimpleHttpServer { public static void main(String args[]) { String docRoot; String indexFile; int port;
ServerSocket serverSkt; Socket clientSkt;
try { BufferedReader buf = new BufferedReader(new InputStreamReader(System.in)); System.out.println("TinyHttpd v0.1"); System.out.print("服务器文件根目录: "); docRoot = buf.readLine(); System.out.print("索引文件: "); indexFile = buf.readLine(); System.out.print("服务器连接埠: "); port = Integer.parseInt(buf.readLine());
if(port < 0 || port > 65535) { port = 80; } } catch(Exception e) { System.err.println("错误: " + e.toString()); System.out.print("采用内定选项"); docRoot = "/var/www/html/"; indexFile = "index.html"; port = 80; System.out.println("文件根目录: " + docRoot + "\n索引文件: " + indexFile + "\n连接埠: " + port); }
try { serverSkt = new ServerSocket(port); System.out.println("倾听客户端于 " + serverSkt.getLocalPort() + " 连接埠....");
while(true) { clientSkt = serverSkt.accept(); System.out.println("客户端连线: " + clientSkt.getInetAddress());
// 启动一个客户端线程 Thread clientThread = new Thread( new HttpClient(clientSkt, docRoot, indexFile)); clientThread.start(); } } catch(IOException e) { e.printStackTrace(); } } }
|