带你实现一个简单的MyApacheTomcat,迷你并发服务器

Apache Tomcat,首先要明确他们之间的关系,Apache是web服务器,Tomcat是应用服务器(Servlet容器),可以认为是Apache的扩展,也就是说Servlet由Tomcat进行处理。
现在我们要通过Socket技术实现Apache Web服务器的一些功能,比如:

------->并发访问(应用线程池)

------->处理GET请求

------->处理POST请求

------->可以部署静态web页面

功能演示如下图:



程序如下,大致就是监听客户端请求,然后使用线程池处理客户端请求,判断请求方式,向客户端展现服务器默认页面。客户端可以进行POST表单提交,服务器接收并作出反馈。可以部署静态页面到服务器,放到webapps文件下即可,访问方式为/hello.html主要应用技术:IO、多线程、Socket。

/**
 * MyTomcat,多线程服务器
 * 
 * @version 0.1
 * @author Syskey
 *
 */
public class MyApacheTomcat {
	public static void main(String[] args) {
		// 初始化线程池
		ExecutorService pool = Executors.newFixedThreadPool(3);
		try {
			ServerSocket server = new ServerSocket(8080);
			while (true) {
				Socket client = server.accept(); // 开始监听
				String ip = client.getInetAddress().getHostAddress();
				int port = client.getPort();
				System.out.println("client [" + ip + "] ::" + port + ":: --- connected");
				pool.execute(new ClientTask(client)); // 使用线程池处理客户端请求
			}
		} catch (IOException e) {
			throw new RuntimeException("服务器异常终止");
		}
	}
}

/**
 * 负责处理客户端请求的任务类
 * @author Syskey
 *
 */
class ClientTask implements Runnable {
	private Socket client;
	private BufferedReader reader;
	private BufferedWriter out;

	public ClientTask(Socket client) {
		this.client = client;
	}

	@Override
	public void run() {
		try {
			String ip = client.getInetAddress().getHostAddress();
			/* 接收请求信息 */
			reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "GBK"));
			// 读取第一行,获取消息头中的请求地址跟请求方式(GET | POST)
			String line = reader.readLine();
			System.out.println(line);
			String resource = ""; // 请求地址
			String method = ""; // 请求方式
			if(line != null && !"".equals(line)) {
				resource = line.substring(line.indexOf("/"), line.lastIndexOf("/")-5);
				method = getMethod(line);
			}
			System.out.println("resource=" + resource);
			System.out.println("method=" + method);
			// 
			int contentLength = 0; // POST数据长度
			while((line = reader.readLine()) != null) {
				if("".equals(line))
					break;
				// System.out.println(line);
				if(line.startsWith("Content-Length")) { // 取得Content-Length
					contentLength = Integer.parseInt(line.substring(line.indexOf(':') + 1).trim());
				}
			}
			// 取得POST表单提交的内容
			String content = "";
			if(contentLength > 0 && method.equals("POST")) {
				System.out.println("POST -------------------- POST");
				char[] buf = new char[contentLength];
				for(int i = 0; i < contentLength; i++) {
					buf[i] = (char) reader.read();
				}
				content = new String(buf);
				System.out.print(URLDecoder.decode(content, "GBK"));
				System.out.println();
			}
			
			System.out.println("请求 -------------------- 结束\n");  
			/*
			 * 在这可以进行判断(resource),默认发送以下数据(服务器主页)。 否则要什么给什么,没有就404
			 */
			/* 发送消息给客户端 */
			out = new BufferedWriter(new OutputStreamWriter(
										client.getOutputStream(), "GBK"));
			if(!resource.equals("/")) { //不是默认资源
				File file = new File("src/webapps" + resource); // 资源文件
				System.out.println(file.getAbsolutePath());
				if (file != null && file.exists()) {
					BufferedReader bufReader = 
							new BufferedReader(
									new InputStreamReader(new FileInputStream(file), "GBK"));
					String req_resource = null;
					while((req_resource = bufReader.readLine()) != null) {
						out.write(req_resource);
					}
					bufReader.close();
				} else { // 请求资源不存在,报404
					out.write("404:出错啦!!!!!!!出门左拐,回到服务器主页");
				}
			} else {
				out.write("<html>");
				out.write("<head>");
				out.write("<title>");
				out.write("我的网站");
				out.write("</title>");
				out.write("</head>");
				out.write("<body>");
				out.write("<center><h1>你好," + ip + ",欢迎来访</h1></center>");
				out.write("<form action='#' method='post'>");
				out.write("<input type='text' name='username' />");
				out.write("用户名<br/>");
				out.write("<input type='password' name='password' />");
				out.write("密码");
				out.write("<input type='submit' value='Submit' />");
				out.write("</form>");
				if(method.equals("POST") && !"".equals(content)) { // POST请求,并且表单有数据
					setPostValue(content); // 保存进Map集合
					out.write("您的用户名是:" + URLDecoder.decode(getPostValue("username"), "GBK")
							+ "\t密码是: " + URLDecoder.decode(getPostValue("password"), "GBK"));
				}
				out.write("</body>");
				out.write("</html>");
			}
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null)
					out.close();
				client.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private Map<String, String> map; // 存放POST键值对信息
	
	/**
	 * 保存键值对信息到Map集合
	 * @param content 原始POST消息
	 */
	private void setPostValue(String content) {
		// String urlRegex = "(^|&|\\?)"+ name + "=([^&]*)(&|$)";
		// username=1111&password=111
		String[] keyValues = content.split("&");
		map = new HashMap<String, String>();
		for(String s : keyValues) {
			String[] keyValue = s.split("="); //username=1111
			map.put(keyValue[0], keyValue[1]);
		}
	}
	
	/**
	 * 获取参数值
	 * @param name 参数名
	 * @return 参数值
	 */
	private String getPostValue(String name) {
		if (map != null && !map.isEmpty())
			return map.get(name);
		return "";
	}
	
	/**
	 * 获取请求方式
	 * @param line 消息头第一行
	 * @return POST | GET
	 */
	private String getMethod(String line) {
		Pattern pattern = Pattern.compile("^(GET|POST)\\b");
		Matcher m = pattern.matcher(line);
		if(m.find()) 
			return m.group();
		return "";
	}
}

原创文章,转载请注明出处: http://blog.csdn.net/thinking_in_android

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个运行于 安卓系统的 小型web服务器,包括php/mysql 配置文件可以修改,另外可以用phpmyadmin 管理数据库。 让你的手机立刻变身小型服务器。 =============================== Turn your Android devices into a web and database server with Palapa Web Server, a suite of web developer. This application has been designed for low memory consumption and CPU usage, specially used for smartphone and tablet. Hey, it's free and you don't need a root access to run Palapa Web Server! # Requirements - Internal memory should not be less than 50MB! - ARM based processor - Minimum Android 2.2 Froyo # Features - Lighttpd 1.4.32 - PHP 5.5.1 - MySQL 5.1.69 - Msmtp 1.4.31 - phpMyAdmin 4.0.4.1 - Web Admin 1.0.1 # Default Document Root - Path : /sdcard/pws/www/ # Default URL - Address : http://127.0.0.1:8080/ # Web Admin Informations - Address : http://127.0.0.1:9999 - Username : admin - Password : admin # MySQL Informations - Host : localhost (127.0.0.1) - Port : 3306 - Username : root - Password : adminadmin # phpMyAdmin Informations - Address : http://127.0.0.1:9999/phpmyadmin - Username : root - Password : adminadmin # Problem? If something is not working properly, please try to restart your phone. # Known Issues As you know, compatibility issue is a big problem of Android phone, I can't test it in all phones. So if it can't work for your phone, just uninstall it, I'm sorry to waste your time. You also can send a mail to let me know your phone model, if I solve it, I will let you know.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值