`

模拟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("<html>");
		out.println("<title>ErrMsg");	
		out.println("</title>");
		out.println("<body>");
		out.println("<h1>ErrorCode:" +  errCode + "ErrMsg:" + errMsg + "</h1>");
		out.println("</body>");
		out.println("</html>");
	}
	
	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

分享到:
评论

相关推荐

    BufferedReader的readLine()方法使用时要注意

    NULL 博文链接:https://wushipan-easy.iteye.com/blog/1831047

    Socket简单编程,利用BufferedReader可以双方传递

    没有堵塞,客户端和服务端简单的信息传递,利用了BufferedReader读。

    Java Socket 编程源代码示例

    BufferedReader input = new BufferedReader( new InputStreamReader(System.in)); try { String line = input.readLine(); out.println(line); in.close(); out.close(); ...

    Android TCP Socket通信实例Demo源码Apk下载

    读取socket输入流的时候很多代码都会这么写,一般也不会有什么问题,但是readLine()方法读取不到换行和回车时会阻塞! String line = null; while ((line = br.readLine()) != null) { } 具体可以先查看博文:...

    BufferedReader 介绍_动力节点Java学院整理

    BufferedReader 是缓冲字符输入流。它继承于Reader。 BufferedReader 的作用是为其他字符输入流添加一些缓冲功能。

    socket编程集萃

    事实上网络编程简单的理解就是两台计算机相互通讯数据而已,对于程序员而言,去掌握一种编程接口并使用一种编程模型相对就会显得简单的多了,Java SDK提供一些相对简单的Api来完成这些工作。Socket就是其中之一,...

    基础深化和提高-常用类

    FileInputStream、FileOutputStream、BufferedReader、BufferedWriter等:用于进行文件和流的输入输出操作,可以读取、写入文件和处理数据流。 字符串处理类: String、StringBuffer、StringBuilder等:用于处理...

    socket应用小程序

    几个很小的socket程序(源码)给其中一个小例: package cn.com.socket; import java.io.*; import java.net.*; public class ServerSocketThread extends Thread{ private Socket socket; private ...

    超级有影响力霸气的Java面试题大全文档

    当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。 20、abstract class和interface有什么区别? ...

    利用Java的Socket网络编程实现小型聊天室

    这个小型的聊天系统我没有用swt去做出界面出来,因为之前用的32位的,现在换了个环境导致之前的包不能用了,只能以控制台进行信息的交互。另外,这里介绍的是基于TCP的,UDP的简单一些就不介绍了。 基本代码 服务端 ...

    TCP编程——网络编程详细源码

    熟练掌握TCP方式的SOCKET编程 public void run() { try { // 构造输入流缓存 BufferedReader bufReader = new BufferedReader( new InputStreamReader(clientInput)); // 按行读取输入内容 ...

    聊天的终端和服务器.txt

    若不是,则在屏幕上输出收到的信息,并由键盘上输入发送到对方的应答信息。请编写程序完成此功能。 mport java.net.*; import java.io.*; class Server{ public Server() { try { ServerSocket ss = new ...

    BufferedReader类

    NULL 博文链接:https://chaoyi.iteye.com/blog/2084140

    java编程基础,应用与实例

    21.2.3 Socket类 394 21.3 单向通信 396 21.3.1 接收字符串的服务器 397 21.3.2 发送字符串的客户机 398 21.4 双向通信 399 21.4.1 传送文件的服务器 400 21.4.2 接收文件的客户机 401 21.4.3 多客户...

    java代码-BufferedReader()总的readLine()函数,注意不需要强制类型转换读取值,用比较字符转函数equals();判断取值是否符合结束条件。

    java代码-BufferedReader()总的readLine()函数,注意不需要强制类型转换读取值,用比较字符转函数equals();判断取值是否符合结束条件。

    基于JAVA本地监听与远程端口扫描的毕业设计,通过JAVA的ServerSocket类,创建ServerSocket对象并绑定

    本地端口监听实现通过JAVA的ServerSocket类,创建ServerSocket对象并绑定要监听的本地端口,然后通过accept()方法接受连接请求,在新线程中处理请求。具体代码如下: ServerSocket ss = new ServerSocket(6666); //监听...

    HttpClient以及获取页面内容应用

    压缩包中含有多个文档,从了解httpclient到应用。 httpClient 1httpClint 1.1简介 HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持...

    HTTP.zip_HTTP 调试_http socket_java http post

    模拟HTTP协议,Java 发送 http 请求 (get 与 post 方法请求 ) , 以下代码经本人亲自调试可用! 可以直接使用之。 注意:通过 BufferedReader 读取远程返回的数据时,必须设置读取编码,否则中文会乱码!

    Java 详解BufferedReader

    详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader

    JAVA的剪刀石头布游戏设计方案.doc

    目 录 1剪刀石头布游戏设计思路阐述2 2程序概要设计2 2.1功能需求分析2 2.2性能需求分析2 2.3程序框图3 2.4 JAVA类及自定义类相互继承的层次关系3 2.4.1 Java类及自定义类的说明3 2.4.2类中成员及作用4 String data...

Global site tag (gtag.js) - Google Analytics