用最基本的socket实现http服务器的功能,上代码:
import java.io.*;
import java.util.*;
import java.net.*;
public class Webserver{
//根资源路径
protected String docroot;
//绑定端口,一般采用二级端口:8080
protected int port;
//监听scoket,监听请求
protected ServerSocket ss;
//内部类对象,用于处理一次请求
class Handler extends Thread{
protected PrintWriter pw;
protected BufferedOutputStream bos;
protected BufferedReader br;
protected File docroot; //所请求的资源
protected Socket socket; //请求的链接
public Handler(Socket _socket,String _docroot) throws Exception{
this.socket=_socket;
this.docroot=new File(_docroot).getCanonicalFile();
}
@Override
public void run(){
try{
br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
bos=new BufferedOutputStream(socket.getOutputStream());
pw=new PrintWriter(new OutputStreamWriter(bos));
String line=br.readLine(); //获得请求命令
socket.shutdownInput(); //关闭输入链接,忽略接下来的数据。
if(line == null){
socket.close();
return;
}
if(line.toUpperCase().startsWith("GET")){ //标准GET请求
StringTokenizer tokens=new StringTokenizer(line," ?");
tokens.nextToken();
String req=tokens.nextToken(); //请求资源的相对路径
String name; //请求资源的完整路径
if(req.startsWith("/") || req.startsWith("\\")){
name=this.docroot+req;
}else{
name=this.docroot+File.separator+req;
}
File file=new File(name).getCanonicalFile();
//保证file的可访问性
if(!file.getAbsolutePath().startsWith(this.docroot.getAbsolutePath())){
pw.println("HTTP/1.0 403 Forbidden");
pw.println();
}else if(!file.exists()){
pw.println("HTTP/1.0 404 File Not Found");
pw.println();
}else if(!file.canRead()){
pw.println("HTTP/1.0 403 Forbidden");
pw.println();
}else if(file.isDirectory()){
//请求的是文件夹
sendDir(bos,pw,file,req);
}else{
//请求的是文件
sendFile(bos,pw,file.getAbsolutePath());
}
}else{ //我们只实现了GET的请求方式
pw.println("HTTP/1.0 501 Not Implemented");
pw.println();
}
pw.flush();
bos.flush();
}catch(Exception e){
e.printStackTrace();
}
try{
socket.close();
}catch(Exception x){
x.printStackTrace();
}
}
//相应文件的内容到浏览器
protected void sendFile(BufferedOutputStream bos,PrintWriter pw,String fileName) throws Exception{
try{
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(fileName));
byte [] data= new byte[10*1024];
int read=bis.read(data);
pw.println("HTTP/1.0 200 Okay"); //先返回状态码
pw.println();
pw.flush();
bos.flush();
while(read!=-1){
bos.write(data,0,read);
read=bis.read(data);
}
bos.flush();
}catch(Exception ex){
pw.flush();
bos.flush();
}
}
//返回文件夹下面的所有资源列表
protected void sendDir(BufferedOutputStream bos,PrintWriter pw,File dir,String req) throws Exception{
try{
pw.println("HTTP/1.0 200 Okay"); //先返回状态码
pw.println();
pw.flush();
pw.print("<html><head><title>Directory of ");
pw.print(req);
pw.print("</title></head><body><h1>Directory of ");
pw.print(req);
pw.println("</h1><table border=\"0\">");
File[] contents=dir.listFiles();
for(int i=0;i<contents.length;i++){
pw.print("<tr>");
pw.print("<td><a href=\"");
pw.print(req);
pw.print(contents[i].getName());
if(contents[i].isDirectory()){
pw.print("/");
}
pw.print("\">");
if(contents[i].isDirectory()){
pw.print("Dir -> ");
}
pw.print(contents[i].getName());
pw.print("</a></td>");
pw.print("</tr>");
}
pw.println("</table></body></html>");
pw.flush();
}catch(Exception ex){
pw.flush();
bos.flush();
}
}
}
//解析命令行传来的参数
//param1:资源的根目录 param2:监听的端口
protected void parseParams(String[] args) throws Exception{
switch(args.length){
case 1:
case 0:
System.err.println("Syntax:<jvm> "+this.getClass().getName()+"docroot port");
System.exit(0);
default:
this.docroot=args[0];
this.port=Integer.parseInt(args[1]);
break;
}
}
//实例化http服务器
public Webserver(String[] args) throws Exception{
System.out.println("Check for parameters");
//解析参数
parseParams(args);
System.out.println("starting web server....");
//监听链接
this.ss=new ServerSocket(this.port);
System.out.println("ok");
for(;;){
Socket accept=ss.accept();
//响应请求
new Handler(accept,docroot).start();
}
}
public static void main(String[] args) throws Exception{
Webserver demo=new Webserver(args);
}
}
运行:在某个文件夹下面放置一些html文件以及一些图片,作为根资源文件夹。然后启动Webserver.java,传递2个参数:param1:刚才新建的根资源文件夹的路径;param2:监听的端口号,然后打开浏览器:http://localhost:8080/。
eg:java Webserver.java /home/volador/test/ 8080
过程很简单,可以根据这个去扩展,实现自己的http服务器。