这里使用java
socket和concurrent包里的ThreadPoolExecutor实现了一个小型的
HTTP服务器,管理入站请求,代码如下:
class="java" name="code">package jHttpNew;
import java.net.*;
import java.io.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class JHTTP extends Thread
{
//文件所在目录
private File documentRootDirectory;
//默认的文件名
private String indexFileName = "index.html";
private ServerSocket server;
public JHTTP(File documentRootDirectory, int port, String indexFileName) throws IOException
{
if (!documentRootDirectory.isDirectory())
{
throw new IOException(documentRootDirectory + " does not exist as a directory");
}
this.documentRootDirectory = documentRootDirectory;
this.indexFileName = indexFileName;
this.server = new ServerSocket(port);
}
public JHTTP(File documentRootDirectory, int port) throws IOException
{
this(documentRootDirectory, port, "index.html");
}
public JHTTP(File documentRootDirectory) throws IOException
{
this(documentRootDirectory, 80, "index.html");
}
public void run()
{
//建立一个Http Request线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3,TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(3),new ThreadPoolExecutor.AbortPolicy());
System.out.println("Accepting connections on port " + server.getLocalPort());
System.out.println("Document Root: " + documentRootDirectory);
while (true)
{
try
{
//使用服务器端socket,接受http请求
Socket request = server.accept();
//用线程池处理http请求
threadPool.execute(new ThreadPoolTask(documentRootDirectory, indexFileName, request));
}
catch (IOException ex)
{
}
}
}
public static void main(String[] args)
{
// get the Document root
File docroot;
try
{
docroot = new File("C:/jhttp_test");
}
catch (ArrayIndexOutOfBoundsException ex)
{
System.out.println("Usage: java JHTTP docroot port indexfile");
return;
}
// set the port to listen on
int port;
try
{
port = Integer.parseInt(args[1]);
if (port < 0 || port > 65535) port = 80;
}
catch (Exception ex)
{
port = 80;
}
try
{
JHTTP webserver = new JHTTP(docroot, port);
webserver.start();
}
catch(IOException ex)
{
System.out.println("Server could not start because of an " + ex.getClass());
System.out.println(ex);
}
}
}
package jHttpNew;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Serializable;
import java.io.Writer;
import java.net.Socket;
import java.util.Date;
import java.util.StringTokenizer;
public class ThreadPoolTask implements Runnable, Serializable
{
private static final long serialVersionUID = 0;
private File documentRootDirectory;
private String indexFileName = "index.html";
private Object threadPoolTaskData;
ThreadPoolTask(File documentRootDirectory,
String indexFileName,
Object tasks)
{
if (documentRootDirectory.isFile())
{
throw new IllegalArgumentException("documentRootDirectory must be a directory, not a file");
}
this.documentRootDirectory = documentRootDirectory;
try
{
this.documentRootDirectory = documentRootDirectory.getCanonicalFile();
}
catch (IOException ex)
{
}
if (indexFileName != null)
this.indexFileName = indexFileName;
this.threadPoolTaskData = tasks;
}
public void run()
{
// for security checks
String root = documentRootDirectory.getPath();
// 建立socket connection对象
Socket connection;
connection = (Socket) threadPoolTaskData;
try
{
String filename;
String contentType;
OutputStream raw = new BufferedOutputStream(
connection.getOutputStream()
);
Writer out = new OutputStreamWriter(raw);
Reader in = new InputStreamReader(
new BufferedInputStream(
connection.getInputStream()
),"ASCII"
);
StringBuffer requestLine = new StringBuffer();
//读取输入流,这里只读第一行
int c;
while (true)
{
c = in.read();
if (c == '\r' || c == '\n') break;
requestLine.append((char) c);
}
String get = requestLine.toString();
// log the request
System.out.println(get);
StringTokenizer st = new StringTokenizer(get);
String method = st.nextToken();
String version = "";
if (method.equals("GET"))
{
filename = st.nextToken();
if (filename.endsWith("/")) filename += indexFileName;
contentType = guessContentTypeFromName(filename);
if (st.hasMoreTokens())
{
version = st.nextToken();
}
File theFile = new File(documentRootDirectory,
filename.substring(1,filename.length()));
if (theFile.canRead()
// Don't let clients outside the document root
&& theFile.getCanonicalPath().startsWith(root))
{
DataInputStream fis = new DataInputStream(
new BufferedInputStream(
new FileInputStream(theFile)
)
);
byte[] theData = new byte[(int) theFile.length()];
fis.readFully(theData);
fis.close();
if (version.startsWith("HTTP "))
{ // send a MIME header
out.write("HTTP/1.0 200 OK\r\n");
Date now = new Date();
out.write("Date: " + now + "\r\n");
out.write("Server: JHTTP/1.0\r\n");
out.write("Content-length: " + theData.length + "\r\n");
out.write("Content-type: " + contentType + "\r\n\r\n");
out.flush();
} // end if
// send the file; it may be an image or other binary data
// so use the underlying output stream
// instead of the writer
raw.write(theData);
raw.flush();
} // end if
//如果文件不存在,返回404
else
{ // can't find the file
if (version.startsWith("HTTP "))
{ // send a MIME header
out.write("HTTP/1.0 404 File Not Found\r\n");
Date now = new Date();
out.write("Date: " + now + "\r\n");
out.write("Server: JHTTP/1.0\r\n");
out.write("Content-type: text/html\r\n\r\n");
}
out.write("<HTML>\r\n");
out.write("<HEAD><TITLE>File Not Found</TITLE>\r\n");
out.write("</HEAD>\r\n");
out.write("<BODY>");
out.write("<H1>HTTP Error 404: File Not Found</H1>\r\n");
out.write("</BODY></HTML>\r\n");
out.flush();
}
}
//这里只是先实现了GET方法,如果用户没有输入GET,那么返回501的返回码,表示方法未实现
else
{ // method does not equal "GET"
if (version.startsWith("HTTP "))
{ // send a MIME header
out.write("HTTP/1.0 501 Not Implemented\r\n");
Date now = new Date();
out.write("Date: " + now + "\r\n");
out.write("Server: JHTTP 1.0\r\n");
out.write("Content-type: text/html\r\n\r\n");
}
out.write("<HTML>\r\n");
out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n");
out.write("</HEAD>\r\n");
out.write("<BODY>");
out.write("<H1>HTTP Error 501: Not Implemented</H1>\r\n");
out.write("</BODY></HTML>\r\n");
out.flush();
}
}
catch (IOException ex)
{
}
finally
{
try
{
connection.close();
}
catch (IOException ex) {}
}
} // end run
public static String guessContentTypeFromName(String name)
{
if (name.endsWith(".html") || name.endsWith(".htm"))
{
return "text/html";
}
else if (name.endsWith(".txt") || name.endsWith(".java"))
{
return "text/plain";
}
else if (name.endsWith(".gif"))
{
return "image/gif";
}
else if (name.endsWith(".class"))
{
return "application/octet-stream";
}
else if (name.endsWith(".jpg") || name.endsWith(".jpeg"))
{
return "image/jpeg";
}
else return "text/plain";
}
}
以上只简单实现了GET方法,去获取服务器某个文件路径下的某个文件。这个http服务器的功能可以扩展到POST和DELETE方法,我们可以自行添加。
在Eclipse里面运行JHTTP类,启动这个服务器,控制台显示信息如下:
在本机上用命令行做试验:
回车后在命令行输入:
GET /index.html
就会显示服务器指定路径下的index.html文件的内容
参考资料:
《java Network Programming》 Elliotte Rusty Harold 著
- 大小: 6 KB
- 大小: 4.6 KB