大可制作:QQ群:31564239(asp|jsp|php|mysql)

Java Gossip: 简单 HTTP 服务器

这个程序改写自O'reilly的Java网路程序设计书中的jhttp.java程序,我将启动的接口作了一些改变,并服务客户端的线程部份独立出来,使这个程序的服务类更具一般性,不受限制于服务器接口的管理方式。

这个程序可以判别客户端请求的资源类型,并传回适当的标头,因为这是一个最简单的HTTP服务器,它不处理客户端的标头,并只接受基本的GET方法。

基本上这个程序一点都不难,线程与Socket的使用都很基本,只要您稍微懂得HTTP协定,都可以看得懂这个程序,有兴趣的可以参照HTTP协定继续完成功能更丰富的HTTP服务器。

以下为程序码内容:
  • HttpClient.java
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();
}
}
}

  • SimpleHttpServer.java
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();
}
}
}