Java多线程 Web服务器简单实现
openkk
12年前
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.net.URLDecoder; import java.util.StringTokenizer; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 用Java语言实现HTTP服务器,首先启动一个java.net.ServerSocket在提供服务的端口上监听连接.向客户返回文本时,可以用 * PrintWriter,但是如果返回二进制数据,则必须使用OutputStream.write(byte[])方法,返回的应答消息字符串可以使用 * String.getBytes()方法转换为字节数组返回,或者使用PrintStream的print()方法写入文本,用 * write(byte[])方法写入二进制数据. * * 以工程所在目录为web的根目录。 在工程的根目录下放一个大概如下的index.html * * <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" * "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta * http-equiv="Content-Type" content="text/html; charset=gbk"> * <title>简单的测试</title> </head> <body> 你好!这是一个 简单的web服务器。<br> * 这是一个图片!<br> * * <form action="/index.html"> <img alt="" src="images/test.gif"><br> * 姓名:<input type="text" name="name" /><br> * 密码:<input type="password" name="pass"></input><br> * <input type="submit"/> </form> </body> </html> * * 放入图片位置: 工程根目录/images/test.gif <br> * 打开浏览器输入http://localhost/index.html 可以展示index.html * * @author rommel1 */ public class SimpleHttpServer { ServerSocket serverSocket;// 服务器Socket ExecutorService pool = Executors.newFixedThreadPool(2); /** * 服务器监听端口, 默认为 80. */ public static int PORT = 80;// 标准HTTP端口 /** * 开始服务器 Socket 线程. */ public SimpleHttpServer() { try { serverSocket = new ServerSocket(PORT); } catch (Exception e) { System.out.println("无法启动HTTP服务器:" + e.getMessage()); } if (serverSocket == null) System.exit(1);// 无法开始服务器 // new Thread(this).start(); System.out.println("HTTP服务器正在运行,端口:" + PORT); while (true) { pool.execute(new Process(serverSocket)); } } /** * 运行服务器主线程, 监听客户端请求并返回响应. */ /** */ /** * 启动 HTTP 服务器 * * @param args */ public static void main(String[] args) { try { if (args.length != 1) { System.out.println("这是一个简单的web服务器 ,端口是: 80."); } else if (args.length == 1) { PORT = Integer.parseInt(args[0]); } } catch (Exception ex) { System.err.println("服务器初始化错误" + ex.getMessage()); } new SimpleHttpServer(); } } class Process extends Thread { private ServerSocket serverSocket;// 服务器Socket Process(ServerSocket serverSocket) { this.serverSocket = serverSocket; } public void run() { try { Socket client = null;// 客户Socket client = serverSocket.accept();// 客户机(这里是 IE 等浏览器)已经连接到当前服务器 if (client != null) { System.out.println("连接到服务器的用户:" + client); try { // 第一阶段: 打开输入流 BufferedReader in = new BufferedReader( new InputStreamReader(client.getInputStream())); System.out.println("客户端发送的请求信息: ***************"); // 读取第一行, 请求地址 System.out.println("http协议头部信息:"); String line = in.readLine(); System.out.println(line); String resource = line.substring(line.indexOf('/'), line.lastIndexOf('/') - 5); // 获得请求的资源的地址 resource = URLDecoder.decode(resource, "gbk");// 反编码 String method = new StringTokenizer(line).nextElement() .toString();// 获取请求方法, GET 或者 POST // 读取浏览器发送过来的请求参数头部信息 while ((line = in.readLine()) != null) { System.out.println(line); if (line.equals("")) break; } System.out.println("http协议头部结束 ***************"); System.out.println("用户请求的资源是:" + resource); System.out.println("请求的类型是: " + method); String params = null; if (resource.indexOf("?") > -1) { params = resource.substring(resource.indexOf("?") + 1); resource = resource.substring(0, resource.indexOf("?")); } // 显示 POST 表单提交的内容, 这个内容位于请求的主体部分 if ("POST".equalsIgnoreCase(method)) { if (params != null) { params += "&" + in.readLine(); } else { params = in.readLine(); } } System.out.println("打印提交的数据:"); printParams(params); // 读取资源并返回给客户端 fileReaderAndReturn(resource, client); // 关闭客户端链接 client.close(); System.out.println("客户端返回完成!"); } catch (Exception e) { System.out.println("HTTP服务器错误:" + e.getMessage()); } } } catch (Exception e) { System.out.println("HTTP服务器错误:" + e.getMessage()); } } /** * 读取一个文件的内容并返回给浏览器端. * * @param fileName * 文件名 * @param socket * 客户端 socket. * @throws IOException */ void fileReaderAndReturn(String fileName, Socket socket) throws IOException { if ("/".equals(fileName)) {// 设置欢迎页面,呵呵! fileName = "/index.html"; } fileName = fileName.substring(1); PrintStream out = new PrintStream(socket.getOutputStream(), true); File fileToSend = new File(fileName); String fileEx = fileName.substring(fileName.indexOf(".") + 1); String contentType = null; // 设置返回的内容类型 // 此处的类型与tomcat/conf/web.xml中配置的mime-mapping类型是一致的。测试之用,就写这么几个。 if ("htmlhtmxml".indexOf(fileEx) > -1) { contentType = "text/html;charset=GBK"; } else if ("jpegjpggifbpmpng".indexOf(fileEx) > -1) { contentType = "application/binary"; } if (fileToSend.exists() && !fileToSend.isDirectory()) { // http 协议返回头 out.println("HTTP/1.0 200 OK");// 返回应答消息,并结束应答 out.println("Content-Type:" + contentType); out.println("Content-Length:" + fileToSend.length());// 返回内容字节数 out.println();// 根据 HTTP 协议, 空行将结束头信息 FileInputStream fis = null; try { fis = new FileInputStream(fileToSend); } catch (FileNotFoundException e) { out.println("<h1>404错误!</h1>" + e.getMessage()); } byte data[]; try { data = new byte[fis.available()]; fis.read(data); out.write(data); } catch (IOException e) { out.println("<h1>500错误!</h1>" + e.getMessage()); e.printStackTrace(); } finally { out.close(); try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } else { out.println("<h1>404错误!</h1>" + "文件没有找到"); out.close(); } } void printParams(String params) throws IOException { if (params == null) { return; } String[] maps = params.split("&"); for (String temp : maps) { String[] map = temp.split("="); System.out.println(map[0] + "==" + map[1]); } } }