一、传统的BIO编程
先用BIO实现一个简单功能:
server端:监听,打印客户端发送过来的内容,并将原内容回复给客户端。
客户端:向服务端发送内容,并打印服务端返回的内容。
服务端代码:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class BioServer { private ServerSocket server; public BioServer(int port) throws IOException { server = new ServerSocket(port); } public void listen() throws IOException { System.out.println("server started........................."); Socket socket = null; try { while (true) { socket = server.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())), true); while (true) { String text = in.readLine(); System.out.println("text from client: " + text); out.println(text); if ("exit".equals(text)) { //out.println("exit"); socket.close(); break; } } } } catch (Exception e) { e.printStackTrace(); } finally { server.close(); } } public static void main(String[] args) throws IOException { BioServer server = new BioServer(9000); server.listen(); } }
客户端代码:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class BioClient { private Socket socket; public BioClient(String host, int port) throws UnknownHostException, IOException { socket = new Socket(host, port); } public void send() throws IOException { try { PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); out.println("呵呵呵"); out.println("hello server"); out.println("哈哈哈"); out.println("exit"); out.flush(); InputStream inputStream=socket.getInputStream(); BufferedReader in = new BufferedReader( new InputStreamReader(inputStream)); while (true) { String text = in.readLine(); System.out.println(text); if ("exit".equals(text)||"busy".equals(text)) { break; } } } finally { socket.close(); } } public static void main(String[] args) throws UnknownHostException, IOException { for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { BioClient client; try { client = new BioClient("127.0.0.1", 9000); client.send(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } } }
这种写法是一个服务线程为多个客户端服务。服务端执行了socket = server.accept()后服务端才能与客户端建立连接,否则客户端一直阻塞等待连接建立,server端没有阻塞在server.accept方法时客户端如果请求连接就会报connection refused异常。当服务端接受了一个客户端的连接就执行22-34行之间的代码开始为客户端服务,服务完成后再继续调用socket = server.accept()并接待下一个客户端。缺点很明显,只要服务端还没有处理完上一个客户端的请求,别的客户端的请求就必须要先阻塞在那里等待。就好像是有一个售票口只有一个售票员,而在外面有一堆等着买票的人一样,只有一个人买到票并离开了,售票员才能为下一个人服务。
升级一下程序,使每个客户端都有一个服务线程为其服务:
服务端代码:
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class BioServer { private ServerSocket server; public BioServer(int port) throws IOException { server = new ServerSocket(port); } public void listen() throws IOException { System.out.println("server started........................."); Socket socket = null; try { while (true) { socket = server.accept(); new Thread(new BioServerThread(socket)).start(); } } catch (Exception e) { e.printStackTrace(); } finally { server.close(); } } public static void main(String[] args) throws IOException { BioServer server = new BioServer(9000); server.listen(); } }
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; public class BioServerThread implements Runnable { private Socket socket; public BioServerThread(Socket socket) throws IOException { this.socket = socket; } @Override public void run() { try { BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())), true); while (true) { String text = in.readLine(); System.out.println(Thread.currentThread().getName() + " text from client: " + text); out.println(text); if ("exit".equals(text)) { //out.println("exit"); socket.close(); break; } } } catch (Exception e) { e.printStackTrace(); } } }
这样一来每一个请求服务端都会单独打开一个线程,但是如果客户端同时请求太多,则会同时打开很多线程,可能会达到系统处理能力的上限从而导致系统崩溃。想象一下为每一个买票的人配一个售票员的场景吧/(ㄒoㄒ)/~~。
可以通过线程池的方式来解决为每个客户端分配一个线程的问题,通过调节线程池的大小使得性能和响应之间达到一个比较好的平衡。
重写服务端代码:
import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import snailxr.bio.thread.BioServerThread; public class BioServer { private ServerSocket server; public BioServer(int port) throws IOException { server = new ServerSocket(port); } public void listen() throws IOException { BlockingQueue<Runnable> block = new ArrayBlockingQueue<Runnable>(100); /** * * 1)当池子大小小于corePoolSize就新建线程,并处理请求 * 2)当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去从workQueue中取任务并处理 * 3)当workQueue放不下新入的任务时,新建线程入池,并处理请求, * 如果池子大小撑到了maximumPoolSize就用RejectedExecutionHandler来做拒绝处理 */ ThreadPoolExecutor pool = new ThreadPoolExecutor(1, // corePoolSize // 池中保存的线程数,包括空闲线程 2,// maximumPoolSize池中允许的最大线程数 30, // 当线程数大于核心时,此为终止前 多余的空闲线程等待新任务的最长时间,单位由下个参数设置。 TimeUnit.MINUTES, // 时间的单位 block, new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println(r.getClass().getName()); System.out.println("无法继续提供服务...................."); try { BioServerThread bioServer = (BioServerThread) r; Socket socket = bioServer.getSocket(); PrintWriter out = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())), true); InputStream in=socket.getInputStream(); out.println("busy"); while(true){ if(in.read()<0){ socket.close();//让客户端先关闭 break; } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } });// 任务队列 System.out.println("server started........................."); Socket socket = null; try { while (true) { socket = server.accept(); BioServerThread thread = new BioServerThread(socket); pool.execute(thread); System.out.println(pool.getActiveCount()); } } catch (Exception e) { e.printStackTrace(); } finally { server.close(); pool.shutdown(); } } public static void main(String[] args) throws IOException { BioServer server = new BioServer(9000); server.listen(); } }
通过上面的程序我们可以看到bio的api比较简单,适用于连接数量比较少的架构。即使是使用了多线程去处理建立连接后的操作,但是由于bio程序在read和write时都会阻塞线程,直到有数据可读或可写,对线程资源造成了极大的浪费,所以如果并发要求比较高的话,bio可能不是很好的选择。
相关推荐
Java BIO (Blocking Input/Output) 是Java标准库中提供的一种基础网络编程模型,它主要用于创建基于TCP/IP的Socket通信服务。在这个"Java BIO Socke示例"中,我们将探讨如何使用Java BIO API来实现简单的Socket通信...
Java BIO NIO AIO Java BIO、NIO、AIO是 Java 中的三种 I/O 模式,每种模式都有其特点和应用场景。下面对每种模式进行详细解释。 Java BIO Java BIO( Blocking I/O)是一种同步阻塞式的 I/O 模式,即服务器实现...
【WuziGame - JAVA BIO的联机五子棋游戏】是一个使用Java编程语言开发的多人在线游戏项目,其中包含了客户端和服务器两部分。在这个游戏中,玩家可以通过网络连接与他人进行实时对战,享受五子棋的乐趣。项目采用BIO...
Java作为一门广泛使用的开发语言,提供了多种I/O(Input/Output)通信模型,包括传统的阻塞I/O(BIO)、非阻塞I/O(NIO)以及异步I/O(AIO)。这些通信模型在不同的场景下有着各自的优势,理解和掌握它们对于优化...
对java io总结时编写的测试代码,包括BIO,NIO,AIO的实现,Java io操作是编程人员经常使用到的,以前只是使用没有对这三种IO做系统的了解,本文将对这三种IO作详细的介绍并附有测试完整代码
Java中的I/O(输入/输出)机制是程序与...在Java中,这五种模型分别对应BIO、NIO、AIO、传统的异步I/O(如Java的Future)以及基于回调的异步I/O。这些模型的选择取决于应用场景的需求,如连接数、操作类型和性能要求。
"Java使用BIO和NIO进行文件操作对比代码示例" Java BIO和NIO是两种不同的输入/输出(IO)模型,在文件操作中发挥着重要作用。BIO(Blocking I/O)是一种同步阻塞IO模式,而NIO(Non-Blocking I/O)是一种同步非阻塞...
《生物信息学与BioJava应用详解》 在生物信息学领域,BioJava是一个重要的开源工具,主要用于处理和分析生物学数据。这个名为“biojava-master”的压缩包包含了BioJava的源码以及相关的说明教程,为研究者和开发者...
BioJava是基于Java编程语言的一个开源生物信息学库,它为生物信息学家提供了一系列工具,用于处理和分析生物学数据。这个库涵盖了多个生物信息学领域,包括序列比对、基因组分析、蛋白质结构和功能预测等。下面我们...
### BioJava教程详解 #### 一、BioJava简介与应用场景 **BioJava**是一个开源的Java类库集合,旨在为生物序列数据分析的应用程序提供一个框架。它包含了丰富的接口和工具,用于处理生物学序列数据,例如DNA、RNA和...
biojava,bioinformatics tools
**生物信息学与bioJava简介** 在IT领域中,生物信息学是一门结合生物学、计算机科学和统计学的交叉学科,主要关注生命科学数据的处理和分析。在生物信息学中,开发各种软件工具和库是至关重要的,以便对基因序列、...
关于“关于bioJava(2)”的这篇博客,作者可能主要讨论了开源生物信息学工具bioJava的第二部分内容。bioJava是一个用Java语言编写的库,主要用于处理生物学数据,如DNA序列、蛋白质序列等。它为生物信息学家提供了...
Java IO应届生培训讲义是一份面向刚毕业的大学生进行Java IO相关知识的培训资料,它涵盖了Java IO的基础知识、不同的IO模型以及Java中的BIO、NIO和AIO高级IO类库。下面详细解释这些知识点: 1. 用户空间和内核空间 ...
BioJava是一个开源项目,它提供了一系列用于处理生物信息学数据的Java类库。BioJava的目标是让程序员能够更容易地分析生物序列数据,如DNA、RNA和蛋白质序列,并执行与序列分析相关的其他任务,如模式搜索、结构预测...
这是biojava的jar包,另外回上传源代码的,由于文件太大所以不能一块上传
BioJava 的设计涵盖了生物信息学的很多方面的编程
全面理解 Java 网络编程 - BIO、NIO、AIO 本课程旨在帮助学生全面理解 Java 网络编程中的 BIO、NIO、AIO 三剑客,掌握 RPC 编程的基础知识,并结合实战项目巩固所学。 一、网络编程三剑客 - BIO、NIO、AIO BIO...
biojava.jar使用说明书,英文版本。请大家看好再下!
在Java中,Socket主要分为两种模式:BIO(Blocking I/O)和NIO(Non-blocking I/O)。这两个模式分别有不同的应用场景和优缺点。 **一、Java Socket BIO** BIO,即阻塞I/O模型,是Java最初提供的网络通信方式。在...