最近写一个简单的程序模拟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(),以免为了等待一个换行/回车符而一直阻塞
相关推荐
`BufferedReader`是Java IO流中的一个类,主要用于读取字符流,它的`readLine()`方法是我们在处理文本数据时经常用到的一个功能,用于逐行读取输入流中的内容。这个方法在处理文件或者网络数据时非常方便,但如果不...
Java Socket网络编程是Java语言中实现网络通信的基础,它提供了低级别的、面向连接的、可靠的字节流服务。在这个基于Java Socket实现的简单模拟QQ聊天程序中,我们主要探讨以下几个核心知识点: 1. **Socket原理**...
Java Socket网络编程是Java开发中一个重要的组成部分,它允许应用程序通过网络进行通信,实现客户端与服务器之间的数据交换。本教程将深入探讨Java Socket编程的基本概念、原理和实践应用。 一、Socket基本概念 ...
Socket网络编程是计算机网络通信的核心技术之一,它允许两台或多台计算机通过互联网进行数据交换。在本学习笔记中,我们将深入探讨Socket编程的基本概念、原理以及如何在实际项目中应用。 首先,Socket是网络通信的...
在本文中,我们将深入探讨Socket模拟服务器的相关知识点,以及如何实现网络通讯数据的接收和处理。 首先,Socket是一种网络通信协议接口,它允许应用程序通过网络进行双向通信。在Java中,Socket类和ServerSocket类...
在处理响应内容时,可能需要对HTML进行解析,以便找出内部链接。例如,使用Jsoup库,我们可以这样找到所有的`<a>`标签(表示链接): ```java Document doc = Jsoup.parse(response.toString()); Elements links = ...
9. **IO 流**:在 Socket 编程中,通常使用 BufferedReader 和 PrintWriter 进行输入输出流的处理,以便进行字符编码的转换和数据的读写。 通过学习和实践这些知识点,开发者可以构建基本的网络通信应用,如聊天室...
Socket编程是计算机网络通信中的重要概念,特别是在Android应用开发中,它允许设备通过TCP/IP协议进行数据传输。在这个“Socket编程简单例子”中,我们将深入理解如何在Android客户端与服务器之间建立连接,发送消息...
在Android平台上进行网络编程是开发应用不可或缺的一部分,无论是获取服务器数据、实时通信还是文件传输,都需要用到网络技术。本文将深入探讨Android中基于Socket和HTTP的网络编程,包括它们的概念、实现方式以及...
在IT行业中,构建一个模拟Tomcat或Servlet服务器是一项高级任务,它要求对网络编程、HTTP协议、Java Servlet规范以及服务器容器有深入理解。这个项目主要涉及以下知识点: 1. **Socket编程**:Socket是网络通信的...
Java Socket网络编程是Java开发中的重要组成部分,它允许应用程序通过网络进行通信,实现客户端与服务器之间的数据交换。在本文中,我们将深入探讨Java Socket的基本概念、工作原理以及如何使用Socket进行实际的网络...
在服务器端,使用 ServerSocket 类来监听客户端的连接,并使用 Socket 对象来处理客户端的请求。 二、Java Socket 编程的实现方法 Java Socket 编程的实现方法可以分为四步: 1. 打开一个 Socket 连接:在客户端...
在Java中,Socket类和ServerSocket类是进行网络编程的核心类,它们分别代表客户端和服务端的连接。 1. 简单服务器端: 在服务器端,我们首先创建一个ServerSocket对象,它会监听指定的端口(在这个例子中用`%%1`...
Java Socket 发送HTTP请求Web Service是一项基础且重要的网络编程技能,尤其在开发分布式系统或集成不同服务时。本文将深入探讨如何使用Java的Socket API来实现这个功能,并结合标签“源码”和“工具”,提供实用的...
Java Socket网络编程是Java开发中实现网络通信的基础,它提供了客户端和服务器端进行数据交换的接口。在Java SDK中,`java.net`包包含了Socket相关的API,使得开发者能够轻松地进行网络编程。 首先,要理解网络编程...
在深入探讨Java网络编程中的非阻塞与阻塞编程之前,我们先来了解这两个概念的基本含义。阻塞编程,通常指的是在程序执行过程中,当某一部分代码遇到I/O操作时,如读写文件或网络通信,整个程序会暂停运行,等待I/O...
Java Socket网络编程是Java语言中实现网络通信的基础,它提供了低级别的、面向连接的和可靠的字节流服务。以下是对给定文件中四个主要部分的知识点详细解释: 1. **简单服务器端**: - `ServerSocket` 类:用于...
Java Socket网络编程是构建基于TCP/IP协议的网络应用程序的关键技术。在这个实例中,我们将深入理解如何使用Java的Socket类和ServerSocket类来实现一个简单的客户机/服务器通信模型。 首先,服务器端的编程开始于...
Socket网络编程是计算机网络中的一种基础通信机制,它允许两台机器通过TCP/IP协议进行数据交换。在Java中,Socket编程提供了丰富的API来实现客户端与服务器端的交互。本项目包含了一个简单的Socket程序,分为“单向...
此类会利用`java.net`和`java.io`包中的功能,前者包含了网络编程所需的基本类和方法,后者则提供了输入/输出流(InputStream/OutputStream)用于读写操作,这在处理网络数据时极为关键。 ##### 2. 准备工作 建立...