前面讲到:Java IO编程全解(一)——Java的I/O演进之路

  网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手建立连接,如果连接建立成功,双方就可以通过网络套接字(Socket)进行通信。

  在基于传统同步阻塞模型开发中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作。连接成功之后,双方通过输入和输出流进行同步阻塞式通信。

  以经典的时间服务器(TimeServer)为例,通过代码分析来回顾和熟悉下BIO编程。

1. BIO通信模型图

  如下图BIO的服务端通信模型:采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理,处理完成之后,通过输出流返回应答给客户端,线程销毁。这就是典型的一请求一应答通信模型。

图1  同步阻塞I/O服务端通信模型(一客户端一线程)

  该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1 的正比关系,犹豫线程是Java虚拟机非常宝贵的系统资源,当线程数膨胀之后,系统的性能将急剧下降,随着并发访问量的继续增大,系统会发生线程堆栈溢出、创建新线程失败等问题,并最终导致进程宕机或者僵死,不能对外提供服务。

2. 同步阻塞式I/O创建的TimeServer

package joanna.yan.bio;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket; public class TimeServer { public static void main(String[] args) {
int port=9090;
if(args!=null&&args.length>0){
try {
port=Integer.valueOf(args[0]);
} catch (Exception e) {
// 采用默认值
}
} ServerSocket server=null; try {
server=new ServerSocket(port);
System.out.println("The time server is start in port:"+port);
Socket socket=null;
while(true){//通过一个无限循环来监听客户端的连接
socket=server.accept();//如果没有客户端接入,则主线程阻塞在ServerSocket的accept操作上。
new Thread(new TimeServerHandler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(server!=null){
System.out.println("The time server close");
try {
server.close();
server=null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
package joanna.yan.bio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date; public class TimeServerHandler implements Runnable{
private Socket socket; public TimeServerHandler(Socket socket) {
this.socket = socket;
} @Override
public void run() {
BufferedReader in=null;
PrintWriter out=null; try {
in=new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
out=new PrintWriter(this.socket.getOutputStream(), true);
String currentTime=null;
String body=null;
while(true){
body=in.readLine();
if(body==null){
break;
}
System.out.println("The time server receive order:"+body);
//如果请求消息为查询时间的指令"QUERY TIME ORDER"则获取当前最新的系统时间。
currentTime="QUERY TIME ORDER".equalsIgnoreCase(body) ?
new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
out.println(currentTime);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!=null){
out.close();
out=null;
}
if(this.socket!=null){
try {
this.socket.close();
this.socket=null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

3. 同步阻塞式I/O创建的TimeClient

  客户端通过Socket创建,发送查询时间服务器的“QUERY TIME ORDER”指令,然后读取服务端的响应并将结果打印出来,随后关闭连接,释放资源,程序退出执行。

package joanna.yan.bio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException; public class TimeClient {
public static void main(String[] args) {
int port=9090;
if(args!=null&&args.length>0){
try {
port=Integer.valueOf(args[0]);
} catch (Exception e) {
// 采用默认值
}
} Socket socket=null;
BufferedReader in=null;
PrintWriter out=null; try {
socket=new Socket("127.0.0.1",port);
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
out=new PrintWriter(socket.getOutputStream(),true);
out.println("QUERY TIME ORDER");
System.out.println("Send order 2 server succeed.");
String resp=in.readLine();
System.out.println("Now is:"+resp); } catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(out!=null){
out.close();
out=null;
}
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
in=null;
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket=null;
}
}
}
}

  我们发现,BIO主要的问题在于每当有一个新的客户端请求接入时,服务端必须创建一个新的线程处理新接入的客户端链路,一个线程只能吃力一个客户端连接。在高性能服务器应用领域,往往需要面向成千上万个客户端的并发连接,这种模型显然无法满足高性能、高并发接入的场景。

  为了改进一线程一连接模型,后来又演进出了一种通过线程池或者消息队列实现1个或者多个线程处理N个客户端的模型,由于它的底层通信机制依然使用同步阻塞I/O,所以被称为“伪异步”。后面我们将通过对伪异步代码的分析,看看伪异步能否满足我们对高性能、高并发接入的诉求。

Java IO编程全解(三)——伪异步IO编程

如果此文对您有帮助,微信打赏我一下吧~

Java IO编程全解(二)——传统的BIO编程的更多相关文章

  1. Java IO编程全解(四)——NIO编程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7793964.html 前面讲到:Java IO编程全解(三)——伪异步IO编程 NIO,即New I/O,这 ...

  2. Java IO编程全解(五)——AIO编程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7794151.html 前面讲到:Java IO编程全解(四)--NIO编程 NIO2.0引入了新的异步通道的 ...

  3. Java io流详解二

    原文地址https://www.cnblogs.com/xll1025/p/6418766.html 一.IO流概述 概述: IO流简单来说就是Input和Output流,IO流主要是用来处理设备之间 ...

  4. Java IO编程全解(三)——伪异步IO编程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7723174.html 前面讲到:Java IO编程全解(二)--传统的BIO编程 为了解决同步阻塞I/O面临 ...

  5. Java IO编程全解(六)——4种I/O的对比与选型

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7804185.html 前面讲到:Java IO编程全解(五)--AIO编程 为了防止由于对一些技术概念和术语 ...

  6. Java IO编程全解(一)——Java的I/O演进之路

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7419117.html JDK1.4之前的早期版本,Java对I/O的支持并不完善,开发人员在开发高性能I/O ...

  7. JAVA IO 类库详解

    JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...

  8. Java IO流详解(二)——File类

    在上一章博客中简单的介绍了Java IO流的一些特征.也就是对文件的输入输出,既然至始至终都离不开文件,所以Java IO流的使用得从File这个类讲起. File类的描述:File类是文件和目录路径 ...

  9. netty学习(二)--传统的bio编程

    网络编程的基本模型是Client/Server模型.也就是两个进程之间进行相互通信,当中服务端提供位置信息( 绑定ip地址和监听port),client通过连接操作向服务端监听的地址发送连接请求,通过 ...

随机推荐

  1. python连接mysql-PyMySql模块

    安装 pip3 install pymysql 使用 输出mysql版本 import pymysql # 打开数据库连接 db = pymysql.connect("localhost&q ...

  2. oracle数据库导出与导入

    一.查询导出库的字符集 3个 1.查询oracle server端的字符集 SQL>select userenv('language') from dual; USERENV('LANGUAGE ...

  3. Django进阶之中间件

    中间件简介 django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法. 在djang ...

  4. Ajax 监听

    $.ajaxSetup({ beforeSend: function (XMLHttpRequest) { alert("ajax请求之前"); } });

  5. idea快捷键使用

    idea                                 eclipse project                           workspace module     ...

  6. Django框架详细介绍---ORM相关操作---select_related和prefetch_related函数对 QuerySet 查询的优化

    Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化 引言 在数据库存在外键的其情况下,使用select_related()和pre ...

  7. CSS 步骤进度条

    ;;; } .wizard li {;; text-align: center; line-height: 30px; height: 30px; background-color: #C3C3C3; ...

  8. C#异步编程基础入门总结

    1.前言 *.NET Framework提供了执行异步操作的三种模式: 异步编程模型(APM)模式(也称为IAsyncResult的模式),其中异步操作要求Begin和End方法(例如,BeginWr ...

  9. HTTPS通信原理

      https的实现原理https用到了多种加密算法来实现通信安全,其中两种基本的加解密算法类型解释如下:(1)对称加密:密钥只有一个,加密解密为同一个密码,且加解密速度快,典型的对称加密算法有DES ...

  10. SQL语句汇总——数据修改、数据查询

    首先创建一张表如下,创建表的方法在上篇介绍过了,这里就不再赘述. 添加新数据: INSERT INTO <表名> (<列名列表>) VALUES (<值列表>)  ...