`

模拟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()方法使用时要注意

    `BufferedReader`是Java IO流中的一个类,主要用于读取字符流,它的`readLine()`方法是我们在处理文本数据时经常用到的一个功能,用于逐行读取输入流中的内容。这个方法在处理文件或者网络数据时非常方便,但如果不...

    基于java socket网络编程实现的简单模拟qq聊天的程序,可实现并发聊天

    Java Socket网络编程是Java语言中实现网络通信的基础,它提供了低级别的、面向连接的、可靠的字节流服务。在这个基于Java Socket实现的简单模拟QQ聊天程序中,我们主要探讨以下几个核心知识点: 1. **Socket原理**...

    JAVA Socket 网络编程教程

    Java Socket网络编程是Java开发中一个重要的组成部分,它允许应用程序通过网络进行通信,实现客户端与服务器之间的数据交换。本教程将深入探讨Java Socket编程的基本概念、原理和实践应用。 一、Socket基本概念 ...

    Socket网络编程学习笔记

    Socket网络编程是计算机网络通信的核心技术之一,它允许两台或多台计算机通过互联网进行数据交换。在本学习笔记中,我们将深入探讨Socket编程的基本概念、原理以及如何在实际项目中应用。 首先,Socket是网络通信的...

    Socket模拟服务器_Socket模拟服务器_

    在本文中,我们将深入探讨Socket模拟服务器的相关知识点,以及如何实现网络通讯数据的接收和处理。 首先,Socket是一种网络通信协议接口,它允许应用程序通过网络进行双向通信。在Java中,Socket类和ServerSocket类...

    Java编程:发送HTTP请求,返回响应内容

    在处理响应内容时,可能需要对HTML进行解析,以便找出内部链接。例如,使用Jsoup库,我们可以这样找到所有的`&lt;a&gt;`标签(表示链接): ```java Document doc = Jsoup.parse(response.toString()); Elements links = ...

    socket网络编程教程

    9. **IO 流**:在 Socket 编程中,通常使用 BufferedReader 和 PrintWriter 进行输入输出流的处理,以便进行字符编码的转换和数据的读写。 通过学习和实践这些知识点,开发者可以构建基本的网络通信应用,如聊天室...

    Socket编程简单例子

    Socket编程是计算机网络通信中的重要概念,特别是在Android应用开发中,它允许设备通过TCP/IP协议进行数据传输。在这个“Socket编程简单例子”中,我们将深入理解如何在Android客户端与服务器之间建立连接,发送消息...

    android 网络编程 客户端完整代码 socket http

    在Android平台上进行网络编程是开发应用不可或缺的一部分,无论是获取服务器数据、实时通信还是文件传输,都需要用到网络技术。本文将深入探讨Android中基于Socket和HTTP的网络编程,包括它们的概念、实现方式以及...

    模拟tomcat、servlet服务器

    在IT行业中,构建一个模拟Tomcat或Servlet服务器是一项高级任务,它要求对网络编程、HTTP协议、Java Servlet规范以及服务器容器有深入理解。这个项目主要涉及以下知识点: 1. **Socket编程**:Socket是网络通信的...

    Java Socket网络编程研究.zip

    Java Socket网络编程是Java开发中的重要组成部分,它允许应用程序通过网络进行通信,实现客户端与服务器之间的数据交换。在本文中,我们将深入探讨Java Socket的基本概念、工作原理以及如何使用Socket进行实际的网络...

    Java socket编程实现两台主机间的通信

    在服务器端,使用 ServerSocket 类来监听客户端的连接,并使用 Socket 对象来处理客户端的请求。 二、Java Socket 编程的实现方法 Java Socket 编程的实现方法可以分为四步: 1. 打开一个 Socket 连接:在客户端...

    Java Socket网络编程

    在Java中,Socket类和ServerSocket类是进行网络编程的核心类,它们分别代表客户端和服务端的连接。 1. 简单服务器端: 在服务器端,我们首先创建一个ServerSocket对象,它会监听指定的端口(在这个例子中用`%%1`...

    java socket 发送http请求webservice.

    Java Socket 发送HTTP请求Web Service是一项基础且重要的网络编程技能,尤其在开发分布式系统或集成不同服务时。本文将深入探讨如何使用Java的Socket API来实现这个功能,并结合标签“源码”和“工具”,提供实用的...

    Java Socket网络编程初级入门

    Java Socket网络编程是Java开发中实现网络通信的基础,它提供了客户端和服务器端进行数据交换的接口。在Java SDK中,`java.net`包包含了Socket相关的API,使得开发者能够轻松地进行网络编程。 首先,要理解网络编程...

    java网络编程(非阻塞与阻塞编程)

    在深入探讨Java网络编程中的非阻塞与阻塞编程之前,我们先来了解这两个概念的基本含义。阻塞编程,通常指的是在程序执行过程中,当某一部分代码遇到I/O操作时,如读写文件或网络通信,整个程序会暂停运行,等待I/O...

    Java_Socket网络编程大全[参照].pdf

    Java Socket网络编程是Java语言中实现网络通信的基础,它提供了低级别的、面向连接的和可靠的字节流服务。以下是对给定文件中四个主要部分的知识点详细解释: 1. **简单服务器端**: - `ServerSocket` 类:用于...

    Java Socket网络编程实例.pdf

    Java Socket网络编程是构建基于TCP/IP协议的网络应用程序的关键技术。在这个实例中,我们将深入理解如何使用Java的Socket类和ServerSocket类来实现一个简单的客户机/服务器通信模型。 首先,服务器端的编程开始于...

    Socket 网络编程

    Socket网络编程是计算机网络中的一种基础通信机制,它允许两台机器通过TCP/IP协议进行数据交换。在Java中,Socket编程提供了丰富的API来实现客户端与服务器端的交互。本项目包含了一个简单的Socket程序,分为“单向...

    Java中的socket网络编程.pdf

    此类会利用`java.net`和`java.io`包中的功能,前者包含了网络编程所需的基本类和方法,后者则提供了输入/输出流(InputStream/OutputStream)用于读写操作,这在处理网络数据时极为关键。 ##### 2. 准备工作 建立...

Global site tag (gtag.js) - Google Analytics