模拟tomcat进行http请求及响应处理:BufferedReader类的readLine在socket网络编程应用时发生阻塞

阅读更多

最近写一个简单的程序模拟tomcat进行http请求及响应处理时,发现使用BufferedReader类的readLine在socket网络编程应用时发生阻塞。

启动服务类:

package com.lwf.server;

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

public class WebServer {

	public static void main(String[] args) {
		int port = 8080;
		if(args != null && args.length == 1){
			port = Integer.parseInt(args[0]);
		}
		new WebServer().startServer(port);
		
	}
	
	public void startServer(int port){
		ServerSocket serverSocket = null;
		try {
			serverSocket = new ServerSocket(port);
			int i = 0;
			while(true){
				System.out.println("server started " + i++);
				Socket socket = serverSocket.accept();
				new Processor(socket).start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

请求处理类:

package com.lwf.server;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

public class Processor extends Thread{
	Socket socket = null;
	InputStream in = null;
	PrintStream out = null;
	OutputStream out1 = null;
	public static final String filePath = "F:";
	public Processor(){	}
	
	public Processor(Socket socket){
		this.socket = socket;
		try {
			in = socket.getInputStream();
			out = new PrintStream(socket.getOutputStream());
			out1 = socket.getOutputStream();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void run() {
		try {
			String fileNamePath = parse(in);
			OutPrintFile(fileNamePath);
			Thread current = Thread.currentThread();
			System.out.println("当前线程:" + current.getName());
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public String parse(InputStream in){
		String retVal = "";
		try {
			BufferedReader bf = new BufferedReader(new InputStreamReader(in));
			retVal = getRequestPath(bf);
			//printParseContent(bf);
			
//			bf.close();  //不能关闭输入流,如果关闭则socket将重置

		} catch (IOException e) {
			e.printStackTrace();
		}
		return retVal;
		
	}

	/** 
	* @Title: getRequestPath 
	* @Description: 获得http请求的资源路径
	* @param @param bf
	* @param @return
	* @param @throws IOException   
	* @return String  
	* @throws 
	*/ 
	private String getRequestPath(BufferedReader bf) throws IOException {
		String retVal;
		String httpMsg = bf.readLine();
		String[] contents = httpMsg.split(" ");
		if(contents.length != 3){
			sendErrorMsg(400, "Client Send Error");
		}
		System.out.println("Method:" + contents[0] + " Resource:" + contents[1] + " Protocol:" + contents[2]);
		retVal = contents[1];
		return retVal;
	}
	
	/** 
	* @Title: printParseContent 
	* @Description: 输出解析出来的http请求信息
	* @param @param bf
	* @param @throws IOException   
	* @return void  
	* @throws 
	*/ 
	private void printParseContent(BufferedReader bf) throws IOException {
		StringBuffer requestStr = new StringBuffer();
		String data = null;
		while((data = bf.readLine()) != null){
			requestStr.append(data + "\n");
		}
		System.out.println(requestStr.toString());
	}

	public void sendErrorMsg(int errCode,String errMsg){
		out.println("HTTP/1.1 " + errCode + " " + errMsg);
		out.println("Content-Type: text/html");
		out.println();
		out.println("");
		out.println("ErrMsg");	
		out.println("");
		out.println("");
		out.println("

ErrorCode:" + errCode + "ErrMsg:" + errMsg + "

"); out.println(""); out.println(""); } public void OutPrintFile(String fileName){ File file = new File(filePath + fileName); if(!file.exists()){ sendErrorMsg(404, "File Not Found !!"); return; } try { outWriteByPrintStream(file); //outWriteByOutPutStream(file); System.out.println("OutPrintFile finish -- " ); } catch (Exception e) { e.printStackTrace(); } } private void outWriteByPrintStream(File file) throws FileNotFoundException, IOException { InputStream in = new FileInputStream(file); byte b [] = new byte[(int)file.length()]; in.read(b); out.println("HTTP/1.1 200 OK"); out.println("Content-Type: text/html"); out.println("Content-Length:"+ b.length); out.println(); out.write(b); in.close(); } @SuppressWarnings("unused") private void outWriteByOutPutStream(File file) throws FileNotFoundException, IOException { byte[] bytes = new byte[1024]; InputStream in = new FileInputStream(file); int ch = in.read(bytes, 0, 1024); while (ch != -1) { out1.write(bytes, 0, ch); ch = in.read(bytes, 0, 1024); } in.close(); } }

 

 将上类的parse方法的printParseContent(bf);取消注释,调试:

如在浏览器输入地址:http://本机IP:8080/Noname1.html (我这里将Noname1.html放在F盘根目录)

当程序运行到printParseContent的while循环时读取几行后程序不再运行。。

跟踪bf来源,BufferedReader bf = new BufferedReader(new InputStreamReader(in));

in = socket.getInputStream();

可见最终来源于socket得到的输入流。。经查

readLine()是一个阻塞函数,当没有数据读取时,就一直会阻塞在那,而不是返回null。

readLine()只有在数据流发生异常或者另一端被close()掉时,才会返回null值。

使用socket之类的数据流时,要避免使用readLine(),以免为了等待一个换行/回车符而一直阻塞

参考文章:http://blog.csdn.net/swingline/article/details/5357581

你可能感兴趣的:(模拟tomcat进行http请求及响应处理:BufferedReader类的readLine在socket网络编程应用时发生阻塞)