`
0428loveyu
  • 浏览: 29127 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

用Java编写一个服务器

阅读更多

一个简单的服务器实现,采用Java语言。

/**
 * 
 */
package iotest.serversocket;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author Brandon B. Lin
 * 
 */
public class JHTTP extends Thread {

	private File documentRootDirectory;
	private String indexFileName = "index.html";
	private ServerSocket server;
	private int threadCount = 50;

	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);
	}

	@Override
	public void run() {
		createThreadPools();
		logServerInfo(server);
		acceptConnection();
	}

	private void createThreadPools() {
		for (int i = 0; i < threadCount; i++) {
			Thread t = new Thread(new RequestProcessor(documentRootDirectory,
					indexFileName));
			t.start();
		}
	}

	private void logServerInfo(ServerSocket server) {
		System.out.println("Accepting connections on port "
				+ server.getLocalPort());
		System.out.println("Document Root: " + documentRootDirectory);
	}

	private void acceptConnection() {
		while (true) {
			try {
				Socket request = server.accept();
				RequestProcessor.processRequest(request);
			} catch (IOException exception) {

			}
		}
	}

	public static void main(String[] args) {
		File root = new File("F:\\Java\\document\\docs");
		int port = 80;
		startServer(root, port);

	}

	private static void startServer(File rootDirectory, int port) {
		try {
			JHTTP webServer = new JHTTP(rootDirectory, port);
			webServer.start();
		} catch (IOException e) {
			System.out.println("Server could not start because of an "
					+ e.getClass());
			e.printStackTrace();
		}
	}

}

/**
 * 
 */
package iotest.serversocket;

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.Writer;
import java.net.Socket;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;

/**
 * @author Brandon B. Lin
 * 
 */
public class RequestProcessor implements Runnable {

	private static List<Socket> socketPool = new LinkedList<>();
	private File documentRootDirectory;
	private String indexFileName = "index.html";

	public RequestProcessor(File documentRootDirectory, String inexFileName) {
		if (documentRootDirectory.isFile()) {
			throw new IllegalArgumentException(
					"DocumentRootDirectory must be a directory, not a file");
		}
		this.documentRootDirectory = documentRootDirectory;
		try {
			this.documentRootDirectory = documentRootDirectory
					.getCanonicalFile();
		} catch (IOException exception) {
			exception.printStackTrace();
		}
		if (inexFileName != null)
			this.indexFileName = inexFileName;
	}

	public static void processRequest(Socket request) {
		synchronized (socketPool) {
			socketPool.add(socketPool.size(), request);
			socketPool.notifyAll();
		}
	}

	@Override
	public void run() {

		while (true) {
			String version = "";
			try (Socket connection = getRequestFromJobQueue()) {
				Reader in = new InputStreamReader(new BufferedInputStream(
						connection.getInputStream()), "ASCII");
				String request = readRequest(in);
				System.out.println(request);

				OutputStream raw = new BufferedOutputStream(
						connection.getOutputStream());
				Writer out = new OutputStreamWriter(raw);

				StringTokenizer stringTokenizer = new StringTokenizer(request);
				String method = stringTokenizer.nextToken();
				if (method.equals("GET")) { // GET
					File requestedFile = getFileFromRequest(stringTokenizer);
					version = getVersionFromRequest(stringTokenizer);
					if (accessiable(requestedFile)) {// OK
						processSucess(raw, requestedFile, version);
					} else { // not file found
						processFailure(out, ResponseState.FNF, version);
					}
				} else { // not GET
					processFailure(out, ResponseState.NIP, version);
				}

			} catch (IOException exception) {
				exception.printStackTrace();
			}
		}

	}

	private Socket getRequestFromJobQueue() {
		synchronized (socketPool) {
			while (socketPool.isEmpty()) {
				try {
					socketPool.wait();
				} catch (InterruptedException exception) {

				}
			}
			return socketPool.remove(0);
		}
	}

	private String readRequest(Reader in) throws IOException {
		StringBuffer requestLine = new StringBuffer();
		int readByte;
		while (true) {
			readByte = in.read();
			if (readByte == '\r' || readByte == '\n')
				break;
			requestLine.append((char) readByte);
		}
		return requestLine.toString();
	}

	private byte[] readRequestedFile(File requestedFile) throws IOException {
		DataInputStream fis = new DataInputStream(new BufferedInputStream(
				new FileInputStream(requestedFile)));
		byte[] theData = new byte[(int) requestedFile.length()];
		fis.readFully(theData);
		fis.close();
		return theData;
	}

	private File getFileFromRequest(StringTokenizer stringTokenizer) {
		String fileName = stringTokenizer.nextToken();
		if (fileName.endsWith("/")) {
			fileName += indexFileName;
		}
		File theFile = new File(documentRootDirectory, fileName.substring(1,
				fileName.length()));
		return theFile;
	}

	private String getVersionFromRequest(StringTokenizer stringTokenizer) {
		String version = "";
		if (stringTokenizer.hasMoreTokens()) {
			version = stringTokenizer.nextToken();
		}
		return version;
	}

	private void processSucess(OutputStream raw, File requestedFile,
			String version) throws IOException {

		byte[] theData = readRequestedFile(requestedFile);
		String contentType = guessContentTypeFromRequest(requestedFile
				.getName());
		if (version.startsWith("HTTP")) {
			writeHeader(new OutputStreamWriter(raw), ResponseState.OK,
					new Content(contentType, theData.length));
		}
		raw.write(theData);
		raw.flush();
	}

	private boolean accessiable(File requestedFile) throws IOException {
		return requestedFile.canRead()
				&& requestedFile.getCanonicalPath().startsWith(
						documentRootDirectory.getPath());
	}

	private void processFailure(Writer out, ResponseState state, String version)
			throws IOException {
		if (version.startsWith("HTTP ")) {
			writeHeader(out, state, new Content("text/html", -1));
		}
		writeHint(out, state);
	}

	private void writeHeader(Writer out, ResponseState state, Content content)
			throws IOException {

		out.write("HTTP/1.0" + state.getStateCode() + state.getHint() + "\r\n");
		Date now = new Date();
		out.write("Data: " + now + "\r\n");
		out.write("Server: JHTTP/1.0 \r\n");
		if (content.getContenLength() != -1) {
			out.write("Content-length: " + content.getContenLength() + "\r\n");
		}
		out.write("Content-Type: " + content.getContentType() + "\r\n\r\n");
		out.flush();
	}

	private void writeHint(Writer out, ResponseState state) throws IOException {
		out.write("<HTML>\r\n");
		out.write("<HEAD><TITLE>" + state.getHint() + "</TITLE>\r\n");
		out.write("</HEAD>\r\n");
		out.write("<BODY>");
		out.write("<H1>HTTP Error " + state.getStateCode() + ": "
				+ state.getHint() + "</H1>\r\n");
		out.write("</BODY></HTML>\r\n");
		out.flush();
	}

	public static String guessContentTypeFromRequest(String request) {
		String exetension = getExtension(request);
		switch (exetension) {
		case "html":
		case "htm":
			return "text/html";
		case "txt":
		case "java":
			return "text/plain";
		case "gif":
			return "image/gif";
		case "class":
			return "application/octet-stream";
		case "jpg":
		case "jpeg":
			return "image/jpeg";
		default:
			return "text/plain";
		}
	}

	public static String getExtension(String fileName) {
		return fileName.substring(fileName.lastIndexOf('.')+1, fileName.length());
	}

	class Content {
		private String contentType;
		private int contenLength;

		public Content(String contentType, int contentLength) {
			this.contentType = contentType;
			this.contenLength = contentLength;
		}

		public String getContentType() {
			return contentType;
		}

		public void setContentType(String contentType) {
			this.contentType = contentType;
		}

		public int getContenLength() {
			return contenLength;
		}

		public void setContenLength(int contenLength) {
			this.contenLength = contenLength;
		}

	}

}

/**
 * 
 */
package iotest.serversocket;

/**
 * @author Brandon B. Lin
 * 
 */
public enum ResponseState {

	OK(200, "OK"), FNF(404, "File Not Found"), NIP(501, "Not Implemented");

	private int stateCode;
	private String hint;

	ResponseState(int stateCode, String hint) {
		this.stateCode = stateCode;
		this.hint = hint;
	}

	public int getStateCode() {
		return stateCode;
	}

	public void setStateCode(int stateCode) {
		this.stateCode = stateCode;
	}

	public String getHint() {
		return hint;
	}

	public void setHint(String hint) {
		this.hint = hint;
	}

}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics