zoukankan      html  css  js  c++  java
  • HTTP服务器(3)

    功能完整的HTTP服务器

    导语

    这个一个功能完备的HTTP服务器。它可以提供一个完整的文档输,包括图像,applet,HTML文件,文本文件。它与SingleFileHttpServer非常相似,只不过它所关注的是GET请求的内容。它会根据GET请求的内容在自己的工作目录查找对应的资源,并将该资源返回给用户。这个服务是相当轻量级的。

    主线程代码

    import java.io.File;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.logging.Logger;
    
    public class JHTTP {
    	//开启日志
    	private static final Logger logger = Logger.getLogger(JHTTP.class.getCanonicalName());
    	//线程数
    	private static final int NUM_THREAD = 50;
    	//默认主页
    	private static final String INDEX_FILE = "index.html";
    	//服务器工作目录
    	private final File rootDirectory;
    	//端口号
    	private final int port;
    	
    	/**
    	 * 
    	 * @param _rootDirectory 工作目录
    	 * @param _port	端口号
    	 */
    	public JHTTP(File _rootDirectory, int _port) {
    		if (!_rootDirectory.isDirectory())
    				throw new RuntimeException(_rootDirectory + "does not exist as a directory");
    		rootDirectory = _rootDirectory;
    		port = _port;
    	}
    	
    	/**
    	 * 启动服务器
    	 * @throws IOException
    	 */
    	public void start() throws IOException {
    		ExecutorService pool = Executors.newFixedThreadPool(NUM_THREAD);
    		try (ServerSocket server = new ServerSocket(port)) {
    			logger.info("Accepting connection on port" + server.getLocalPort());
    			logger.info("Document Root: " + rootDirectory);
    			while (true) {
    				try {
    					Socket request = server.accept();
    					pool.execute(new RequestProcessor(rootDirectory, INDEX_FILE, request));
    				} catch (IOException e) {
    					logger.warning("Error accepting connection");
    				}
    			}
    		}
    	}
    	
    	public static void main(String[] args) {
    		
    		//设置工作目录
    		File docroot;
    		try {
    			docroot = new File(args[0]);
    		} catch (ArrayIndexOutOfBoundsException e) {
    			System.out.println("Usage: java JHTTP docroot port");
    			return;
    		}
    		
    		//设置监听端口号
    		int port;
    		try {
    			port = Integer.parseInt(args[1]);
    			if (port < 0 || port > 65535) port = 8080;
    		} catch (RuntimeException e) {
    			port = 8080;
    		}
    		
    		try {
    			JHTTP webserver = new JHTTP(docroot, port);
    			webserver.start();
    		} catch (IOException e) {
    			logger.severe("Server cloud not start");
    		}
    	}
    }
    

    主线程代码比较简单,默认监听8080端口,将连接提交给工作线程来处理。

    处理线程

    import java.io.BufferedOutputStream;
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.Writer;
    import java.net.Socket;
    import java.net.URLConnection;
    import java.nio.file.Files;
    import java.util.Date;
    import java.util.logging.Logger;
    
    public class RequestProcessor implements Runnable {
    
    	private final static Logger logger = Logger.getLogger(RequestProcessor.class.getCanonicalName());
    	private File rootDirectory;
    	private String indexFileName = "index.html";
    	private Socket conn;
    	
    	
    	public RequestProcessor(File _rootDirectory, String _indexFileName,
    			Socket _conn) {
    		if (_rootDirectory.isFile()) 
    			throw new IllegalArgumentException("rootDirectory muse be a directory, not a file");
    		rootDirectory = _rootDirectory;
    		indexFileName = _indexFileName;
    		conn = _conn;
    	}
    
    	
    
    	@Override
    	public void run() {
    		String root = rootDirectory.getPath();
    		try {
    			BufferedOutputStream raw = new BufferedOutputStream(conn.getOutputStream());
    			Writer out = new BufferedWriter(new OutputStreamWriter(raw, "utf-8"));
    			BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    			String get = in.readLine();
    			if (get != null) {
    				logger.info(conn.getRemoteSocketAddress() + " " + get);
    				String[] pieces = get.split("\s+");
    				String method = pieces[0];
    				String version = "";
    				if (method.equals("GET")) {
    					String fileName = pieces[1];
    					if (fileName.endsWith("/")) fileName += indexFileName;
    					String contentType = URLConnection.getFileNameMap().getContentTypeFor(root +fileName);
    					if (pieces.length > 2) {
    						version = pieces[2]; 
    					}
    					File theFile = new File(rootDirectory, fileName.substring(1, fileName.length()));
    					if (theFile.canRead() && theFile.getCanonicalPath().startsWith(root)) {
    						byte[] theData = Files.readAllBytes(theFile.toPath());
    						if (version.startsWith("HTTP/"))
    							sendHeader(out, "HTTP/1.1 200 OK", contentType, theData.length);
    						raw.write(theData);
    						raw.flush();
    						raw.close();
    					} else { //无法找到文件
    						String body = "<html><head><title>File not found</title></head><body>Error 404:文件未找到</body></html>";
    						if (version.startsWith("HTTP/"))
    							sendHeader(out, "HTTP/1.1 4O4 File Not Found", "text/html;charset=utf-8", body.getBytes("utf-8").length);
    						out.write(body);
    						out.flush();
    						out.close();
    					}
    				} else {
    					String body = "<html><head><title>File not found</title></head><body>Error 501:无法处理该请求</body></html>";
    					if (version.startsWith("HTTP/"))
    						sendHeader(out, "HTTP/1.1 5O1 Not Implemented", "text/html;charset=utf-8", body.getBytes("utf-8").length);
    					out.write(body);
    					out.flush();
    					out.close();
    				}
    			}
    		} catch (IOException e){
    			logger.warning("Error talking to " + conn.getRemoteSocketAddress());
    		} finally {
    			try {
    				conn.close();
    			} catch (IOException e) {}
    		}
    	}
    	
    	private void sendHeader(Writer out, String responseCode, String contentType, int length) throws IOException {
    		out.write(responseCode + "
    ");
    		out.write("Date: " + new Date() + "
    ");
    		out.write("Server: JHTTP 2.0
    ");
    		out.write("Content-Type: " + contentType + "
    ");
    		out.write("Content-Length: " + length + "
    
    ");
    		out.flush();
    	}
    }
    

    在处理线程中处理客户端的请求,通过解析GET请求的资源从本地中查找对应的资源。如果没有找的则返回404错误

  • 相关阅读:
    软件工程第四次作业
    软件工程第三次作业
    软件工程第二次作业
    软件工程第一次作业
    [Java数据结构与算法]简单排序之插入排序
    软件工程第四次作业
    软件工程第三次作业
    软件工程第二次作业
    字符串转化为 List 集合
    IO流读写文件中文乱码的解决
  • 原文地址:https://www.cnblogs.com/xidongyu/p/6224230.html
Copyright © 2011-2022 走看看