前两天,利用线程池技术(ThreadPool)写了个web服务器,其性能当然无法和apache iis等相比,但基本的功能都有了,唯一欠缺的是无法解析动态页面,采用解释执行(asp模式的)效率太低,如果采用编译执行,要么自己编写一个编译器来编译整个动态页面,要么采用预编译,很复杂 。。。。
现在把代码拿出来晒一晒!由于只是初步的设计所以没有考虑到很多设计模式,代码在优化上很不到位,请各位高手不吝赐教。
MainServer.java 这是主服务文件,也是提供主线程的类,主线程将请求分发给其他业务线程(workerthread)出来
package com.threadpool;
import java.net.ServerSocket;
public class MainServer
{
public static int clientCount = 0;
//ThreadPool threadPool = null;
int port;
PoolManager poolm;
public MainServer(int port)
{
poolm=PoolManager.getInstance();
poolm.creatThreadPool(100, ActionWorker.class);
this.port = port;
}
public void start() throws Exception
{
ServerSocket ss = new ServerSocket(port);
System.out.println("MainServer is starting.....");
while(true)
{
clientCount++;
poolm.doService(ss.accept());
System.out.println(clientCount+"connections");
}
}
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception
{
// TODO Auto-generated method stub
MainServer server = new MainServer(80);
server.start();
}
}
PoolManager.java 线程池管理器,该类负责管理线程池,如创建新线程,回收线程等等。
package com.threadpool;
import java.net.Socket;
import Pool.ThreadWorker;
public class PoolManager
{
//singleton pattern
private static PoolManager instance = null;
ThreadPool threadPool = null;
private PoolManager()
{
}
public synchronized static PoolManager getInstance()
{
if(instance == null)
instance = new PoolManager();
return instance;
}
//create thread pool
public void creatThreadPool(int max, Class<ActionWorker> worker)
{
try
{
threadPool = new ThreadPool(max, worker);
System.out.println("create a threadpool...");
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private WorkerThread getWorker() throws Exception
{
return threadPool.getWorker();
}
public void doService(Object o)
{
try
{
getWorker().wake((Socket)o);
System.out.println(Thread.currentThread().getName());
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
WorkerThread.java 业务线程类,负责处理具体的请求。
package com.threadpool;
import java.net.Socket;
public class WorkerThread extends Thread
{
private IWorker worker;
private Socket data;
private ThreadPool pool;
WorkerThread(String id, IWorker worker, ThreadPool pool)
{
super(id);
this.worker = worker;
this.pool = pool;
this.data = null;
}
public synchronized void wake(Socket data)
{
this.data = data;
System.out.println("wake up..." + Thread.currentThread().getName());
notify();
}
public synchronized void run()
{
//boolean stop = false;
System.out.println("run....");
while(true)
{
if(data == null)
{
try
{
wait();
System.out.println(Thread.currentThread().getName()+"wait...");
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
continue;
}
}
System.out.println(this.getName()+"are working"+Thread.currentThread().getName());
worker.run(data);
data = null;
if(!pool.pushBack(this))
break;
}
}
}
IWorker.java为业务逻辑接口
package com.threadpool;
public interface IWorker
{
public void run(Object data);
}
ActionWorker.java真正干活的那个类,称为业务逻辑类,与j2ee中的javaBean对应。
package com.threadpool;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
public class ActionWorker implements IWorker
{
public void run(Object data)
{
handleRequest((Socket)data);
}
private void handleRequest(Socket s)
{
try
{
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
Request request = new Request(is);
request.parse();
// // create Response object
Response response = new Response(os);
response.setRequest(request);
response.sendStaticResource();
System.out.println("worker is working..");
MainServer.clientCount--;
//执行完毕后关闭socket,释放线程
s.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
Requset.java封装请求的类,主要用于提取被请求的文件
package com.threadpool;
import java.io.IOException;
import java.io.InputStream;
public class Request
{
private InputStream input;
private String uri;
public Request(InputStream input)
{
this.input = input;
}
//从请求中解析出文件名
public void parse()
{
StringBuffer request = new StringBuffer(2048);
int len;
byte[] buffer = new byte[2048];
try
{
len = input.read(buffer);
}
catch (IOException e)
{
e.printStackTrace();
len = -1;
}
for (int i=0; i<len; i++)
{
request.append((char) buffer[i]);
}
System.out.print(request.toString());
uri = parseUri(request.toString());
}
//截取请求的文件名
private String parseUri(String requestString)
{
int index1, index2;
index1 = requestString.indexOf(' ');
if (index1 != -1)
{
index2 = requestString.indexOf(' ', index1 + 1);
if (index2 > index1)
return requestString.substring(index1 + 1, index2);
}
return null;
}
public String getUri()
{
return uri;
}
}
Response.java 封装相应流的类
package com.threadpool;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Response
{
private static final int BUFFER_SIZE = 1024;
public Request request;
public OutputStream output;
public Response(OutputStream output)
{
this.output = output;
}
public void setRequest(Request request)
{
this.request = request;
}
public void sendStaticResource() throws IOException
{
byte[] bytes = new byte[BUFFER_SIZE];
FileInputStream fis = null;
try
{
File file = new File(System.getProperty("user.dir")+File.separator+"webroot", request.getUri());
if (file.exists())
{
fis = new FileInputStream(file);
int ch = fis.read(bytes, 0, BUFFER_SIZE);
while (ch!=-1)
{
output.write(bytes, 0, ch);
ch = fis.read(bytes, 0, BUFFER_SIZE);
}
}
else
{
// file not found
String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: 23\r\n" +
"\r\n" +
"<h1>File Not Found</h1>";
output.write(errorMessage.getBytes());
}
}
catch (Exception e)
{
// thrown if cannot instantiate a File object
System.out.println(e.toString() );
}
finally
{
if (fis!=null)
fis.close();
}
}
}
在class文件夹下建立 webroot文件夹作为网站的根目录,把网页文件放在下面就可以通过 http://localhost/yourfilename 访问了,简单的服务器就写出来了,由于使用了池技术所以其原理更接近于真正的webserver.
ps: apache服务器是用纯c编写的,其实现的复杂程度的确让人难以想象。