最近写一个简单的程序模拟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(),以免为了等待一个换行/回车符而一直阻塞
相关推荐
NULL 博文链接:https://wushipan-easy.iteye.com/blog/1831047
没有堵塞,客户端和服务端简单的信息传递,利用了BufferedReader读。
BufferedReader input = new BufferedReader( new InputStreamReader(System.in)); try { String line = input.readLine(); out.println(line); in.close(); out.close(); ...
读取socket输入流的时候很多代码都会这么写,一般也不会有什么问题,但是readLine()方法读取不到换行和回车时会阻塞! String line = null; while ((line = br.readLine()) != null) { } 具体可以先查看博文:...
BufferedReader 是缓冲字符输入流。它继承于Reader。 BufferedReader 的作用是为其他字符输入流添加一些缓冲功能。
事实上网络编程简单的理解就是两台计算机相互通讯数据而已,对于程序员而言,去掌握一种编程接口并使用一种编程模型相对就会显得简单的多了,Java SDK提供一些相对简单的Api来完成这些工作。Socket就是其中之一,...
FileInputStream、FileOutputStream、BufferedReader、BufferedWriter等:用于进行文件和流的输入输出操作,可以读取、写入文件和处理数据流。 字符串处理类: String、StringBuffer、StringBuilder等:用于处理...
几个很小的socket程序(源码)给其中一个小例: package cn.com.socket; import java.io.*; import java.net.*; public class ServerSocketThread extends Thread{ private Socket socket; private ...
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。 20、abstract class和interface有什么区别? ...
这个小型的聊天系统我没有用swt去做出界面出来,因为之前用的32位的,现在换了个环境导致之前的包不能用了,只能以控制台进行信息的交互。另外,这里介绍的是基于TCP的,UDP的简单一些就不介绍了。 基本代码 服务端 ...
熟练掌握TCP方式的SOCKET编程 public void run() { try { // 构造输入流缓存 BufferedReader bufReader = new BufferedReader( new InputStreamReader(clientInput)); // 按行读取输入内容 ...
若不是,则在屏幕上输出收到的信息,并由键盘上输入发送到对方的应答信息。请编写程序完成此功能。 mport java.net.*; import java.io.*; class Server{ public Server() { try { ServerSocket ss = new ...
NULL 博文链接:https://chaoyi.iteye.com/blog/2084140
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的ServerSocket类,创建ServerSocket对象并绑定要监听的本地端口,然后通过accept()方法接受连接请求,在新线程中处理请求。具体代码如下: ServerSocket ss = new ServerSocket(6666); //监听...
压缩包中含有多个文档,从了解httpclient到应用。 httpClient 1httpClint 1.1简介 HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持...
模拟HTTP协议,Java 发送 http 请求 (get 与 post 方法请求 ) , 以下代码经本人亲自调试可用! 可以直接使用之。 注意:通过 BufferedReader 读取远程返回的数据时,必须设置读取编码,否则中文会乱码!
详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader详解BufferedReader
目 录 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...