zoukankan      html  css  js  c++  java
  • Java实现一个简易HTTP服务器(三)

    从InputStream读取数据,构造Request。Request包含Http请求的参数。

    public class Request {
    	public String method; // 请求方法
    	public String path; // 请求路径
    	public String portal; // 协议名称
    	public Map<String, String> map; // 请求头中的附加参数
    	public String payload; // 请求体
    
    	private int BUFFER_LEN = 10240;
    
    	public Request(InputStream in) throws IOException {
    		byte[] buf = new byte[BUFFER_LEN];
    		int len = in.read(buf);
    		String reqString = new String(buf, 0, len);
    		String raw = reqString;
    		int i = 0, j = 0;
    
    		// 获取请求方式
    		for (; i < raw.length(); i++)
    			if (raw.charAt(i) == ' ') {
    				this.method = raw.substring(j, i);
    				break;
    			}
    		j = ++i;
    		// 获取请求路径
    		for (; i < raw.length(); i++)
    			if (raw.charAt(i) == ' ') {
    				this.path = raw.substring(j, i);
    				break;
    			}
    		j = ++i;
    		// 获取协议版本
    		for (; i < raw.length(); i++)
    			if (raw.charAt(i) == '
    ') {
    				this.portal = raw.substring(j, i);
    				break;
    			}
    		j = (i += 2);
    
    		this.map = new HashMap<String, String>();
    		String key = "", value = "";
    		while (i < raw.length()) {
    			if (raw.charAt(i) != ':') {
    				i++;
    			} else {
    				key = raw.substring(j, i);
    				j = (i += 2);
    				while (i != raw.length() && raw.charAt(i) != '
    ')
    					i++;
    				value = raw.substring(j, i);
    				map.put(key, value);
    				if (i == raw.length()) {
    					break;
    				} else {
    					j = (i += 2);
    					if (raw.charAt(i) == '
    ') {
    						payload = raw.substring(i + 2);
    					}
    				}
    			}
    
    		}
    
    	}
    
    	@Override
    	public String toString() {
    		return "Request [method=" + method + ", path=" + path + ", portal=" + portal + ", map=" + map + ", payload="
    				+ payload + "]";
    	}
    
    }
    
    

    Response 向输出流中写入参数。类中定义了部分用到的方法。

    package cdbb.httpd;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    
    public class Response {
    	private OutputStream out;
    
    	public String portal;
    	public String status;
    	public String statusDescribe;
    	public Map<String, String> map;
    
    	public Response(OutputStream out, String portal, String status, String statusDescribe) {
    		this.out = out;
    		this.portal = portal;
    		this.status = status;
    		this.statusDescribe = statusDescribe;
    	}
    
    	public void writeHeaderAndBody(byte[] b, int off, int len) {
    		this.writeHeader();
    		this.writeBytes(b, off, len);
    	}
    
    	public void addHeader(String key, String value) {
    		this.map.put(key, value);
    	}
    
    	public void delHeader(String key) {
    		if (this.map.containsKey(key))
    			this.map.remove(key);
    	}
    
    	public void editHeader(String key, String value) {
    		if (this.map.containsKey(key))
    			this.map.replace(key, value);
    	}
    
    	public void writeHeader() {
    		try {
    			String tmp = portal + " " + status + " " + statusDescribe + "
    ";
    			this.writeBytes(tmp.getBytes(), 0, tmp.length());
    			if (map != null) {
    				Iterator<Map.Entry<String, String>> entries = map.entrySet().iterator();
    				while (entries.hasNext()) {
    					Entry<String, String> entry = entries.next();
    					String s = entry.getKey() + " " + entry.getValue() + "
    ";
    					this.writeBytes(s.getBytes(), 0, s.length());
    				}
    			}
    			this.out.write('
    ');
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    
    	public void writeBytes(byte[] b, int off, int len) {
    		try {
    			this.out.write(b, off, len);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    
    }
    
    

    在浏览器和服务端建立起tcp连接后获得socket,一个连接对应一个socket。socket调用Request和Response处理请求

    package cdbb.httpd;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    
    public class Handler implements Runnable {
    	public Socket socket;
    
    	public Handler(Socket socket) {
    		this.socket = socket;
    	}
    
    	@Override
    	public void run() {
    		try {
    			InputStream in = socket.getInputStream();
    			Request req = new Request(in);
    			System.out.println(req);
    
    			if ("/".equals(req.path)) {
    				req.path = "index.html";
    			}
    			if ("/favicon.ico".equals(req.path)) {
    				req.path = "favicon.ico";
    			}
    			File file = new File(req.path);
    			InputStream fin = new FileInputStream(file);
    			int len = 0;
    			byte[] buf = new byte[1024];
    
    			OutputStream out = socket.getOutputStream();
    			Response res = new Response(out, "HTTP/1.1", "200", "OK");
    			res.writeHeader();
    			while ((len = fin.read(buf)) > 0)
    				res.writeBytes(buf, 0, len);
    
    			socket.close();
    			fin.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    }
    
    

    建立和浏览器的连接,并采用线程池技术调用Handler进行具体的处理

    package cdbb.httpd;
    
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Date;
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author cdbb
     */
    public class Server {
    
    	public static void main(String[] args) throws IOException {
    		ServerSocket serverSocket = new ServerSocket(80);
    		System.out.println("Server started at " + new Date() + "
    ");
    
    		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 5, 200, TimeUnit.MILLISECONDS,
    				new ArrayBlockingQueue<Runnable>(5), Executors.defaultThreadFactory(),
    				new ThreadPoolExecutor.AbortPolicy());
    		try {
    			while (true) {
    				// 通信socket的获得
    				Socket socket = serverSocket.accept();
    				threadPoolExecutor.execute(new Handler(socket));
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    			serverSocket.close();
    		}
    
    	}
    }
    
    
  • 相关阅读:
    SQL Server2005重新安装不上的问题及其解决(转)
    取消2003默认共享
    自写生成实体类工具
    双核886针CPU简明制作教程
    VS 2008 在安装SP1后智能提示变成英文的解决办法
    VS2008 安装盘的问题
    拖放 DataGrid 列摘自MSDN
    VB.net SP1 的兼容性问题
    Windows Server 2008+VS2008
    Combobox 的解决方法
  • 原文地址:https://www.cnblogs.com/cdbb/p/12558169.html
Copyright © 2011-2022 走看看