这里使用java socket和concurrent包里的ThreadPoolExecutor实现了一个小型的HTTP服务器,管理入站请求,代码如下:
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
分享到:
相关推荐
死磕ThreadPoolExecutor线程池.pdf!!死磕ThreadPoolExecutor线程池.pdf死磕ThreadPoolExecutor线程池.pdf死磕ThreadPoolExecutor线程池.pdf
主要为大家详细介绍了ThreadPoolExecutor线程池的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
ThreadPoolExecutor线程池
提供工厂方法来创建不同类型的线程池,这篇文章主要介绍了Java ThreadPoolExecutor 线程池的使用介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来...
主要介绍了解决python ThreadPoolExecutor 线程池中的异常捕获问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
在《阿里巴巴java开发手册》中...另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。
ThreadPoolExecutor的使用和Android常见的4种线程池使用介绍
线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor实战及其原理分析(下)线程池ThreadPoolExecutor...
在开发过程中,合理地使用线程池能够带来3个好处: 降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗; 提高响应速度。 当任务到达时,任务可以不需要等到线程创建就能立即执行; 提高...
下面小编就为大家带来一篇简单谈谈ThreadPoolExecutor线程池之submit方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
1.资源简介:PyQt5中使用多线程模块QThread解决了PyQt5界面程序执行比较耗时操作时,程序卡顿出现的无响应以及界面输出无法实时显示的问题,采用线程池ThreadPoolExecutor解决了ping多个IP多任务耗时问题。...
一个关于java 线程池的例子,也适合android
JDK1[1].5中的线程池(ThreadPoolExecutor)使用简介
下面小编就为大家带来一篇ThreadPoolExecutor线程池原理及其execute方法(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
相比 threading 等模块,该模块通过 submit 返回的是一个 future 对象,它是一个未来可期的对象,通过它可以获悉线程的状态主线程(或进程)中可以获取某一个线程(进程)执行的状态或者某一个任务执行的状态及返回值: ...
Java 线程池学习 Reference: 《创建Java线程池》[1],《Java线程:新特征-线程池》[2], 《Java线程池学习》[3]...[5]中有线程池的实例讲解,实现了一个基于线程池的端口监听服务器。★ [6]中有对源码比较细致的分析
NULL 博文链接:https://happysoul.iteye.com/blog/1117090
(转)线程池:java_util_ThreadPoolExecutor 比较详细的介绍了ThreadPoolExecutor用法与属性